Tutorial de Docker

Sep 2020

Aprenda a construir e implementar sus aplicaciones distribuidas fácilmente en la nube con Docker

Qué es Docker?

Wikipedia define Docker como un proyecto de código abierto que automatiza la implementación de aplicaciones de software dentro de contenedores al proporcionar una capa adicional de abstracción y automatización de la virtualización a nivel de sistema operativo en Linux.

En palabras más simples, Docker es una herramienta que permite a los desarrolladores, administradores de sistemas, etc. implementar fácilmente sus aplicaciones en un entorno aislado (llamados contenedores ) para que se ejecuten en el sistema operativo host, es decir, Linux. El beneficio clave de Docker es que permite a los usuarios empaquetar una aplicación con todas sus dependencias en una unidad estandarizada para el desarrollo de software. A diferencia de las máquinas virtuales, los contenedores no tienen una sobrecarga elevada y, por lo tanto, permiten un uso más eficiente del sistema y los recursos subyacentes.

¿Qué son los contenedores?

El estándar de la industria hoy en día es usar máquinas virtuales (VM) para ejecutar aplicaciones de software. Las máquinas virtuales ejecutan aplicaciones dentro de un sistema operativo invitado, que se ejecuta en hardware virtual alimentado por el sistema operativo host del servidor.

Las máquinas virtuales son excelentes para proporcionar un aislamiento completo del proceso para las aplicaciones: hay muy pocas formas en que un problema en el sistema operativo host puede afectar el software que se ejecuta en el sistema operativo invitado, y viceversa. Pero este aislamiento tiene un gran costo: la sobrecarga computacional gastada en la virtualización del hardware para que un SO huésped la use es sustancial.

Los contenedores adoptan un enfoque diferente: al aprovechar la mecánica de bajo nivel del sistema operativo host, los contenedores proporcionan la mayor parte del aislamiento de las máquinas virtuales a una fracción de la potencia informática requerida.

¿Por qué usar contenedores?

Los contenedores ofrecen un mecanismo de empaquetamiento lógico en el que las aplicaciones pueden abstraerse del entorno en el que realmente se ejecutan. Este desacoplamiento permite que las aplicaciones basadas en contenedores se implementen de manera fácil y consistente, independientemente de si el entorno objetivo es un centro de datos privado, la nube pública o incluso la computadora portátil personal de un desarrollador. Esto brinda a los desarrolladores la capacidad de crear entornos predecibles que están aislados del resto de las aplicaciones y que se pueden ejecutar en cualquier lugar.

Desde el punto de vista de las operaciones, además de los contenedores de portabilidad, también le dan un control más granular sobre los recursos, lo que le brinda a su infraestructura una mayor eficiencia que puede resultar en una mejor utilización de sus recursos informáticos.

Debido a estos beneficios, los contenedores (y Docker) han tenido una adopción generalizada. Empresas como Google, Facebook, Netflix y Salesforce aprovechan los contenedores para hacer que los grandes equipos de ingeniería sean más productivos y mejorar la utilización de los recursos informáticos.

¿Qué me enseñará este tutorial?

Este tutorial pretende ser la ventanilla única para ensuciarse las manos con Docker. Además de desmitificar el paisaje de Docker, le dará experiencia práctica en la construcción y despliegue de sus propias aplicaciones web en la nube.

Este documento contiene una serie de secciones, cada una de las cuales explica un aspecto particular de Docker. En cada sección, estaremos escribiendo comandos (o escribiendo código). Todo el código utilizado en el tutorial está disponible en el repositorio de Github.

Nota: Este tutorial usa la versión 19.03.8-ce de Docker. Si encuentra que alguna parte del tutorial es incompatible con una versión futura, háganoslo saber. ¡Gracias!

Requisitos de Docker

No se necesitan habilidades específicas para este tutorial más allá de una comodidad básica con la línea de comando y el uso de un editor de texto. La experiencia previa en el desarrollo de aplicaciones web será útil, pero no es necesaria. A medida que avancemos en el tutorial, haremos uso de algunos servicios en la nube. Si está interesado en seguirlo, cree una cuenta en el sitio que se indica (es gratis):

Utilizaremos esta cuenta para alojar públicamente las imágenes que construya. No se preocupe, cuando se trate de una aplicación empresarial podrá alojar la imagen en un registro privado.

Configurando su computadora

Obtener toda la configuración de herramientas en su computadora puede ser una tarea desalentadora, pero afortunadamente a medida que Docker se ha estabilizado, poner Docker en funcionamiento en su sistema operativo favorito se ha vuelto muy fácil.

Hasta hace unos pocos lanzamientos, ejecutar Docker en OSX y Windows era bastante complicado. Últimamente, sin embargo, Docker ha invertido significativamente en mejorar la experiencia de incorporación para sus usuarios en estos sistemas operativos, por lo que ejecutar Docker ahora es un juego de niños. La guía de instalación de Docker tiene instrucciones detalladas para configurar Docker en Mac, Linux y Windows.

Una vez que haya terminado de instalar Docker, pruebe su instalación de Docker ejecutando lo siguiente:

docker run hello-world

La salida del comando debería aparecer un mensaje similar al siguiente:

Hello from Docker. This message shows that your installation appears to be working correctly. ...

Docker BusyBox

Ahora que tenemos todo configurado, es hora de ensuciarnos las manos. En esta sección, vamos a ejecutar un contenedor Busybox en nuestro sistema y probar el comando [docker run].

Para comenzar, ejecutemos lo siguiente en nuestra terminal:

docker pull busybox

Dependiendo de cómo haya instalado Docker en su sistema, es posible que vea un error de permission denied después de ejecutar el comando anterior. Si está en una Mac, asegúrese de que el motor Docker esté funcionando. Si está en Linux, entonces prefije sus comandos de docker con sudo. Alternativamente, puede crear un grupo de usuarios para deshacerse de este problema.

El comando pull extrae la imagen de busybox del registro Docker y la guarda en nuestro sistema. Puede usar el comando docker images para ver una lista de todas las imágenes en su sistema.

docker images

Da como lugar, una salida similar a:

REPOSITORY TAG     IMAGE ID      CREATED      VIRTUAL SIZE
busybox    latest  c51f86c28340  4 weeks ago  1.109 MB

Docker Run

Ejecutemos ahora un contenedor Docker basado en esta imagen. Para hacer eso, vamos a usar el comando todo poderoso docker run.

docker run busybox

¿No pasó nada? Sí, detrás de la escena, sucedieron muchas cosas. Cuando llama a run, el cliente Docker encuentra la imagen (busybox en este caso), carga el contenedor y luego ejecuta un comando en ese contenedor. Cuando ejecutamos [docker run busybox], no proporcionamos un comando, por lo que el contenedor se inició, ejecutó un comando vacío y luego salió. Variemos un poco la prueba:

docker run busybox echo "hello from busybox"
hello from busybox

Bien, finalmente vemos algo de salida. En este caso, el cliente Docker ejecutó obedientemente el comando echo en nuestro contenedor busybox y luego lo cerró. Si te has dado cuenta, todo eso sucedió bastante rápido. Imagine arrancar una máquina virtual, ejecutar un comando y luego matarlo. ¡Ahora sabes por qué dicen que los contenedores son rápidos! Ok, ahora es el momento de ver el comando docker ps. El comando [docker ps] muestra todos los contenedores que se están ejecutando actualmente.

docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Como no se están ejecutando contenedores, vemos una línea en blanco. Probemos una variante más útil:

docker ps -a
CONTAINER    ID IMAGE     COMMAND   CREATED         STATUS                     PORTS   NAMES
305297d7a235 busybox      "uptime"  11 minutes ago  Exited (0) 11 minutes ago          distracted_goldstine
ff0a5c3750b9 busybox      "sh"      12 minutes ago  Exited (0) 12 minutes ago          elated_ramanujan
14e5bd11d164 hello-world  "/hello"   2 minutes ago  Exited (0) 2 minutes ago           thirsty_euclid

Entonces, lo que vemos arriba es una lista de todos los contenedores que hemos ejecutado. Tenga en cuenta que la columna STATUS muestra que estos contenedores salieron hace unos minutos.

Probablemente se esté preguntando si hay una manera de ejecutar más de un comando en un contenedor. Probemos eso ahora:

docker run -it busybox sh
# Dentro del contenedor
# ls
bin dev etc home proc root sys tmp usr var
# uptime
05:45:21 up 5:58, 0 users, load average: 0.00, 0.01, 0.04

Ejecutar el comando run con los indicadores -it nos une al terminal interactivo en el contenedor. Ahora podemos ejecutar tantos comandos en el contenedor como queramos. Tómese un tiempo para ejecutar sus comandos favoritos.

Si te sientes particularmente aventurero, puedes probar [rm -rf /bin] en el contenedor. Asegúrese de ejecutar este comando en el contenedor y no en su computadora portátil / escritorio. Hacer esto no hará que otros comandos como ls, uptime funcionen. Una vez que todo deja de funcionar, puede salir del contenedor (escriba exit y presione Entrar) y luego vuelva a iniciarlo con el comando [docker run -it busybox sh]. Como Docker crea un nuevo contenedor cada vez, todo debería comenzar a funcionar nuevamente, por tanto los contenedores son volátiles.

El comando [docker run], que probablemente sea el comando que usará con más frecuencia. Tiene sentido dedicar un tiempo a sentirse cómodo con él. Para obtener más información acerca de la run, use docker run –help para ver una lista de todos los indicadores que admite. A medida que avanzamos, veremos algunas variantes más de docker run.

Sin embargo, antes de seguir adelante, hablemos rápidamente sobre la eliminación de contenedores. Vimos arriba que todavía podemos ver los restos del contenedor incluso después de haber salido ejecutando [docker ps -a]. A lo largo de este tutorial, ejecutará [docker run] varias veces y dejar contenedores extraviados consumirá espacio en disco. Por lo tanto, como regla general, limpie los contenedores una vez que haya terminado con ellos. Para hacer eso, puede ejecutar el comando docker rm. Simplemente copie las ID del contenedor desde arriba y péguelas junto con el comando.

docker rm 305297d7a235 ff0a5c3750b9 305297d7a235 ff0a5c3750b9

Al eliminarlo, debería ver las identificaciones repetidas. Si tiene que eliminar un montón de contenedores de una vez, las ID de copiado y pegado pueden ser tediosas. En ese caso, simplemente puede ejecutar:

docker rm $(docker ps -a -q -f status=exited)

Este comando elimina todos los contenedores que tienen un estado de exited. En caso de que se lo pregunte, el indicador -q solo devuelve los ID numéricos y la salida de los filtros -f según las condiciones proporcionadas. Una última cosa que será útil es el indicador –rm que se puede pasar a [docker run] que elimina automáticamente el contenedor una vez que sale de él.

En versiones posteriores de Docker, el comando de docker container prune se puede utilizar para lograr el mismo efecto.

docker container prune
WARNING! This will remove all stopped containers. Are you sure you want to continue ? \[y/N\]
# y Deleted Containers:
4a7f7eebae0f63178aff7eb0aa39f0627a203ab2df258c1a00b456cf20063
f98f9c2aa1eaf727e4ec9c0283bcaa4762fbdba7f26191f26c97f64090360
Total reclaimed space: 212 B

Por último, también puede eliminar imágenes que ya no necesita ejecutando docker rmi.

Terminología en Docker

En la última sección, utilizamos una gran cantidad de jerga específica de Docker que podría ser confusa para algunos. Entonces, antes de continuar, permítanme aclarar alguna terminología que se usa con frecuencia en el ecosistema Docker.

  • Imágenes: los fotografía de nuestra aplicación lista para ejecutar que forman la base de los contenedores. En la demostración anterior, utilizamos el comando [docker pull] para descargar la imagen busybox.
  • Contenedores: creados a partir de imágenes de Docker y ejecutan la aplicación real. Creamos un contenedor con [docker run], lo que hicimos con la imagen de busybox que descargamos. Se puede ver una lista de contenedores en ejecución con el comando [docker ps].
  • Docker Daemon: el servicio en segundo plano que se ejecuta en el host que administra la construcción, ejecución y distribución de contenedores Docker. El daemon es el proceso que se ejecuta en el sistema operativo con el que los clientes hablan.
  • Docker Client: la herramienta de línea de comandos que permite al usuario interactuar con el demonio. En términos más generales, también puede haber otras formas de clientes, como Kitematic, que proporcionan una GUI a los usuarios.
  • Docker Hub: un registro de imágenes de Docker. Puede pensar en el registro como un directorio de todas las imágenes Docker disponibles. Si es necesario, uno puede alojar sus propios registros Docker y puede usarlos para extraer imágenes.

Webapps con Docker

¡Excelente! Así que ahora hemos visto [docker run], hremos jugamos con un contenedor Docker y también aprendimos algo de terminología. Armados con todo este conocimiento, ahora estamos listos para llegar a lo real, es decir, desplegar aplicaciones web con Docker.

Sitios Estáticos

Comencemos dando pequeños pasos. Lo primero que veremos es cómo podemos ejecutar un sitio web estático muy simple. Vamos a extraer una imagen de Docker de Docker Hub, ejecutar el contenedor y ver qué fácil es ejecutar un servidor web.

Vamos a empezar. La imagen que vamos a utilizar es un sitio web de una sola página que ya hemos creado con el propósito de esta demostración y alojado en el registro : arteco/static-app. Podemos descargar y ejecutar la imagen directamente de una vez usando docker run. Como se señaló anteriormente, el indicador –rm elimina automáticamente el contenedor cuando sale.

docker run --rm arteco/static-app

Como la imagen no existe localmente, el cliente primero buscará la imagen del registro y luego la ejecutará. Si todo va bien, debería ver que se Nginx is running… mensaje Nginx is running… en su terminal. Bien, ahora que el servidor se está ejecutando, ¿cómo ver el sitio web? ¿En qué puerto se está ejecutando? Y lo que es más importante, ¿cómo accedemos al contenedor directamente desde nuestra máquina host? Presiona Ctrl + C para detener el contenedor.

Bueno, en este caso, el cliente no está exponiendo ningún puerto, por lo que debemos volver a ejecutar el comando docker run para publicar puertos. Mientras estamos en eso, también debemos encontrar una manera de que nuestra terminal no esté conectada al contenedor en ejecución. De esta manera, puede cerrar felizmente su terminal y mantener el contenedor en funcionamiento. Esto se llama modo separado.

docker run -d -P --name static-app arteco/static-app
596531db867c055a819ab433e39fbd98517d52bd07c78023ee80aaaa805a3e5b

En el comando anterior, -d desconectará nuestra terminal, -P publicará todos los puertos expuestos a puertos aleatorios y finalmente –name corresponde al nombre que queremos dar. Ahora podemos ver los puertos ejecutando el comando docker port [CONTAINER]

docker port static-app
80/tcp -> 0.0.0.0:32768

Puede abrir http://localhost:32768 en su navegador.

Nota: Si está usando docker-toolbox, entonces es posible que necesite usar docker-machine ip default para obtener la IP.

También puede especificar un puerto personalizado al que el cliente reenviará las conexiones al contenedor.

docker run -p 8888:80 arteco/static-app
Nginx is running...

Para detener un contenedor separado, ejecute docker stop dando la ID del contenedor. En este caso, podemos usar el nombre static-app que usamos para iniciar el contenedor.

docker stop static-app

Estoy seguro de que estás de acuerdo en que fue súper simple. Para implementar esto en un servidor real, solo necesitará instalar Docker y ejecutar el comando Docker anterior. Ahora que ha visto cómo ejecutar un servidor web dentro de una imagen Docker, debe preguntarse: ¿cómo creo mi propia imagen Docker? Esta es la pregunta que exploraremos en la siguiente sección.

Imágenes de Docker

Hemos visto imágenes antes, pero en esta sección profundizaremos en lo que son las imágenes de Docker y crearemos nuestra propia imagen. Por último, también usaremos esa imagen para ejecutar nuestra aplicación localmente y finalmente desplegarla en Docker Hub para compartirla con nuestros amigos. ¿Emocionado? ¡Excelente! Empecemos.

Las imágenes de Docker son la base de los contenedores. En el ejemplo anterior, extrajimos la imagen de Busybox del registro y le pedimos al cliente Docker que ejecutara un contenedor basado en esa imagen. Para ver la lista de imágenes que están disponibles localmente, use el comando docker images.

docker images
REPOSITORY              TAG     IMAGE ID      CREATED       VIRTUAL SIZE
arteco/static-app       latest  b270625a1631  21 hours ago  133.9 MB
busybox                 latest  c51f86c28340   9 weeks ago  1.109 MB
hello-world             latest  0a6ba66e537a  11 weeks ago  960 B

Lo anterior proporciona una lista de imágenes que saqué del registro, junto con las que hemos creado (en breve veremos cómo). El TAG refiere a una instantánea particular de la imagen y la IMAGE ID es el identificador único correspondiente para esa imagen.

Para simplificar, puede pensar en una imagen similar a un repositorio git: las imágenes pueden confirmarse con cambios y tener múltiples versiones. Si no proporciona un número de versión específico, el cliente tiene el latest predeterminado. Por ejemplo, puede extraer una versión específica de la imagen de ubuntu

docker pull ubuntu:18.04

Para obtener una nueva imagen de Docker, puede obtenerla de un registro (como Docker Hub) o crear la suya propia. Hay decenas de miles de imágenes disponibles en Docker Hub. También puede buscar imágenes directamente desde la línea de comandos mediante la docker search.

Una distinción importante a tener en cuenta cuando se trata de imágenes es la diferencia entre las imágenes base y las imágenes secundarias.

Las imágenes base son imágenes que no tienen imagen principal, generalmente imágenes con un sistema operativo como ubuntu, busybox o debian.

Las imágenes secundarias son imágenes que se basan en imágenes base y agregan funcionalidad adicional.

Luego están las imágenes oficiales y de usuario, que pueden ser imágenes base y secundarias.

Las imágenes oficiales son imágenes que la gente de Docker mantiene y respalda oficialmente. Estos son típicamente una palabra de largo. En la lista de imágenes de arriba, las imágenes de python, ubuntu, busybox y hello-world son imágenes oficiales.

Las imágenes de usuario son imágenes creadas y compartidas por usuarios como usted y yo. Se basan en imágenes base y agregan funcionalidad adicional. Por lo general, estos están formateados como nombre de user/image-name.

Cómo crear una imagen

Ahora que tenemos una mejor comprensión de las imágenes, es hora de crear la nuestra. Nuestro objetivo en esta sección será crear una imagen que proteja una simple aplicación Flask. Para los propósitos de este taller, ya he creado una pequeña aplicación con Python Flask que muestra un texto Html servido dinámicamente. Si aún no lo ha hecho, continúe y clone el repositorio localmente así:

git clone https://github.com/arteco/docker-tutorial.git
cd docker-tutorial

Esto debe clonarse en la máquina donde está ejecutando los comandos de Docker y no dentro de un contenedor de Docker.

El siguiente paso ahora es crear una imagen con esta aplicación web. Como se mencionó anteriormente, todas las imágenes de usuario se basan en una imagen base. Como nuestra aplicación está escrita en Python, la imagen base que vamos a utilizar será Python 3.

Qué es Dockerfile

Un Dockerfile es un archivo de texto simple que contiene una lista de comandos a los que llama el cliente Docker mientras crea una imagen. Es una forma sencilla de automatizar el proceso de creación de imágenes. La mejor parte es que los comandos que escribe en un Dockerfile son casi idénticos a sus comandos de Linux equivalentes. Esto significa que realmente no tiene que aprender una nueva sintaxis para crear sus propios dockerfiles.

El directorio de la aplicación contiene un Dockerfile, pero como lo hacemos por primera vez, crearemos uno desde cero. Para comenzar, cree un nuevo archivo en blanco en nuestro editor de texto favorito y guárdelo en la misma carpeta que la aplicación del matraz con el nombre de Dockerfile.

Comenzamos especificando nuestra imagen base. Use la palabra clave FROM para hacer eso:

FROM python: 3

El siguiente paso generalmente es escribir los comandos para copiar los archivos e instalar las dependencias. Primero, configuramos un directorio de trabajo y luego copiamos todos los archivos de nuestra aplicación.

#set a directory for the app
WORKDIR  /usr/src/app
# copy all the files to the container
COPY  . .

Ahora que tenemos los archivos, podemos instalar las dependencias.

RUN pip install --no-cache-dir -r requirements.txt

Lo siguiente que debemos especificar es el número de puerto que debe exponerse. Como nuestra aplicación de matraz se ejecuta en el puerto 5000, eso es lo que indicaremos.

EXPOSE 5000

El último paso es escribir el comando para ejecutar la aplicación, que es simplemente: python ./app.py. Usamos el comando CMD para hacer eso:

CMD  [ "python", "./app.py" ]

El propósito principal de CMD es decirle al contenedor qué comando debe ejecutar cuando se inicia. Con eso, nuestro Dockerfile ya está listo. Así es como esto luce

FROM python: 3
# set a directory for the app
WORKDIR  /usr/src/app
# copy all the files to the container
COPY  . .
# install dependencies RUN  pip install --no-cache-dir -r requirements.txt
# tell the port number the container should expose
EXPOSE 5000
# run the command
CMD  [ "python", "./app.py" ]

Ahora que tenemos nuestro Dockerfile, podemos construir nuestra imagen. El comando de docker build hace el trabajo pesado de crear una imagen Docker desde un Dockerfile.

La siguiente sección muestra el resultado de ejecutar lo mismo. Antes de ejecutar el comando usted mismo (no olvide el punto), asegúrese de reemplazar mi nombre de usuario con el suyo. Este nombre de usuario debe ser el mismo que creó cuando se registró en Docker Hub. Si aún no lo ha hecho, continúe y cree una cuenta. El comando docker build es bastante simple: toma un nombre de etiqueta opcional con -t y una ubicación del directorio que contiene el Dockerfile.

docker build -t yourusername/flask-app .
Sending build context to Docker daemon 8.704 kB
Step 1 : FROM python:3 # Executing 3 build triggers...
Step 1 : COPY requirements.txt /usr/src/app/ ---> Using cache
Step 1 : RUN pip install --no-cache-dir -r requirements.txt ---> Using cache
Step 1 : COPY . /usr/src/app ---> 1d61f639ef9e Removing intermediate container 4de6ddf5528c
Step 2 : EXPOSE 5000 ---> Running in 12cfcf6d67ee ---> f423c2f179d1 Removing intermediate container 12cfcf6d67ee
Step 3 : CMD python ./app.py ---> Running in f01401a5ace9 ---> 13e87ed1fbc2 Removing intermediate container f01401a5ace9
Successfully built 13e87ed1fbc2

Si no tiene la imagen python:3, el cliente primero extraerá la imagen y luego creará su imagen. Por lo tanto, su salida de ejecutar el comando se verá diferente a la mía. Si todo salió bien, ¡tu imagen debería estar lista! Ejecute las docker images y vea si se muestra su imagen.

El último paso en esta sección es ejecutar la imagen y ver si realmente funciona (reemplazando mi nombre de usuario con el tuyo).

docker run -p 8888:5000 yourusername/flask-app
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

El comando que acabamos de ejecutar usó el puerto 5000 para el servidor dentro del contenedor y lo expuso externamente en el puerto 8888. Dirígete a la URL con el puerto 8888, donde tu aplicación debería estar activa.

¡Felicidades! Ha creado con éxito su primera imagen acoplable.

Publicar una imagen

Hay muchos registros Docker diferentes que puede usar (incluso puede alojar el suyo). Por ahora, usemos Docker Hub para publicar la imagen. Para publicar, solo escriba

docker push yourusername/flask-app

Si es la primera vez que presiona una imagen, el cliente le pedirá que inicie sesión. Proporcione las mismas credenciales que utilizó para iniciar sesión en Docker Hub.

docker login Username: yourusername
WARNING: login credentials saved in /Users/yourusername/.docker/config.json
Index Succeeded

Recuerde reemplazar el nombre de la etiqueta de la imagen anterior con la suya. Es importante tener el formato de username/image_name de username/image_name para que el cliente sepa dónde publicar.

Una vez hecho esto, puede ver su imagen en Docker Hub. Por ejemplo, aquí está la página web de mi imagen.

Nota: Una cosa que nos gustaría aclarar antes de seguir adelante es que no es imprescindible alojar su imagen en un registro público (o en cualquier registro). En caso de que esté escribiendo código para el próximo inicio de unicornio de un millón de dólares, puede omitir totalmente este paso. La razón por la que estamos promocionando nuestras imágenes públicamente es que hace que la implementación sea muy simple al omitir algunos pasos de configuración intermedios.

Ahora que su imagen está en línea, cualquiera que tenga instalada la ventana acoplable puede jugar con su aplicación escribiendo un solo comando.

docker run -p 8888:5000 yourusername/flask-app

Si se ha esforzado por configurar entornos de desarrollo locales / compartir la configuración de la aplicación en el pasado, sabe muy bien lo increíble que esto suena. ¡Es por eso que Docker es tan genial!

Tutorial de Docker

¿Con ganas de seguir leyendo?

Nuestra guía de Java

Cerca de 450 páginas en un libro de tapa blanda que podrás utilizar para aprender a programar en Java desde cero sin conocimientos previos. Explicamos como usar las herramientas más usadas en el mundo empresarial, todas ellas son totalmente gratis y Open Source.

Aprende conceptos como TDD para desarrollar software con garantías. Conecta tus apps con JPA en bases de datos SQL. Integra tus proyectos con Maven y mantenlos bajo control con Git. Mantente al día con la programación funcional de Java 8+.

Nuestra guía de Java
Libro Javañol