Cómo desarrollar contenedores con Dockerfiles

1. Descripción general

Docker es una plataforma abierta para desarrollar, enviar y ejecutar aplicaciones. Permite separar las aplicaciones de la infraestructura y tratar a la infraestructura como una aplicación administrada. Docker ayuda a enviar, implementar y probar código más rápido y a acortar el ciclo entre su escritura y ejecución.

Para esto, combina las funciones de creación de contenedores de kernel con flujos de trabajo y herramientas que ayudan a implementar y administrar aplicaciones.

Los contenedores de Docker pueden usarse directamente en Kubernetes, lo que permite ejecutarlos de manera sencilla en Kubernetes Engine. Después de aprender los aspectos esenciales de Docker, contarás con las habilidades para empezar a desarrollar aplicaciones de Kubernetes y alojadas en contenedores.

Qué aprenderás

En este lab, aprenderás a realizar las siguientes tareas:

  • Crea un Dockerfile para una aplicación de ejemplo
  • Compila una imagen
  • Ejecuta la imagen como un contenedor de manera local
  • Cambia el comportamiento del contenedor
  • Envía la imagen a Artifact Registry

Requisitos previos

Este es un lab de nivel introductorio. Parte de la suposición de que la experiencia en Docker y contenedores que tiene el alumno es escasa o nula. Contar con conocimientos de Cloud Shell y la línea de comandos es recomendable, pero no es obligatorio.

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una string de caracteres que no se utiliza en las API de Google y se puede actualizar en cualquier momento.
  • El ID del proyecto debe ser único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). Cloud Console genera automáticamente una string única, que, por lo general, no importa cuál sea. En la mayoría de los codelabs, debes hacer referencia al ID del proyecto (suele ser PROJECT_ID). Por lo tanto, si no te gusta, genera otro aleatorio o prueba con uno propio y comprueba si está disponible. Después de crear el proyecto, este ID se “congela” y no se puede cambiar.
  • Además, hay un tercer valor, el Número de proyecto, que usan algunas API. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en Cloud Console para usar las API o los recursos de Cloud. Ejecutar este codelab no debería costar mucho, tal vez nada. Si quieres cerrar los recursos para no se te facture más allá de este instructivo, sigue las instrucciones de “limpieza” que se encuentran al final del codelab. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de USD 300.

2. Aplicación de muestra

Se proporcionó una aplicación de ejemplo para facilitar este lab. En esta sección, recuperarás el código fuente y compilarás la aplicación en su forma nativa antes de pasar al proceso de creación de contenedores.

Código fuente

El código fuente de este lab está disponible en el repositorio GoogleCloudPlatform/container-developer-workshop, junto con la documentación de la aplicación de muestra.

Configurar Git

git config --global user.name ${USER}
git config --global user.email ${USER}@qwiklabs.net

Clona la aplicación de ejemplo Cloud Source Repository

gcloud source repos clone sample-app ${HOME}/sample-app &&
cd ${HOME}/sample-app &&
git checkout main

Salida

Cloning into '/home/student_03_49720296e995/sample-app'...
remote: Finding sources: 100% (16/16)
remote: Total 16 (delta 0), reused 16 (delta 0)
Receiving objects: 100% (16/16), 47.23 KiB | 681.00 KiB/s, done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.

Project [qwiklabs-gcp-02-4327c4e03d82] repository [sample-app] was cloned to [/home/student_03_49720296e995/sample-app].
Branch 'main' set up to track remote branch 'main' from 'origin'.
Switched to a new branch 'main'

Compila la aplicación de ejemplo

cd ${HOME}/sample-app
./mvnw compile

Salida

[INFO] Scanning for projects...
...
[INFO] Compiling 1 source file to /home/student_03_49720296e995/sample-app/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.080 s
[INFO] Finished at: 2022-02-23T17:14:30Z
[INFO] ------------------------------------------------------------------------

Ejecuta la aplicación de ejemplo

cd ${HOME}/sample-app
./mvnw exec:java

Salida

[INFO] Scanning for projects...
...
Listening at http://localhost:8080

Obtén una vista previa de la aplicación en ejecución

  • Haz clic en el botón Vista previa en la Web de Cloud Shell
  • Haz clic en Vista previa en el puerto 8080

Cuando finalices, haz lo siguiente:

  • Presiona CTRL + C en Cloud Shell para detener la aplicación en ejecución.

3. Dockerfile

Aloja la aplicación en contenedores con un Dockerfile

Un método para empaquetar una aplicación en un contenedor es usar un Dockerfile. El Dockerfile es similar a una secuencia de comandos que le indica al daemon cómo ensamblar la imagen del contenedor. Consulta la documentación de referencia de Dockerfile) para obtener más información.

Crear un Dockerfile vacío en el repositorio de la aplicación de ejemplo

touch ${HOME}/sample-app/Dockerfile

Abre el Dockerfile en el editor que prefieras.

vi ${HOME}/sample-app/Dockerfile

Elige una imagen de inicio

Usar el método de Dockerfile para compilar un contenedor requiere conocimiento directo sobre la aplicación para ensamblar el contenedor. El primer paso para crear un Dockerfile es seleccionar una imagen que se utilizará como la base de tu imagen.Esta imagen debe ser una imagen superior o base que una fuente de confianza, como la empresa, mantiene y publica.

La instrucción FROM inicializa una nueva etapa de compilación y establece la imagen base para los comandos secuenciales posteriores. Por lo tanto, la instrucción FROM suele ser la primera instrucción en un Dockerfile y solo puede estar precedida por una instrucción ARG opcional para admitir variables.

Sintaxis: FROM <image>[:<tag> | @<digest>] [AS <name>]

El formato de una imagen es <image>:<tag> o <image>@<digest>. Si no se especifica una etiqueta o un resumen, el valor predeterminado es la etiqueta :latest. El formato de <image> varía según el registro que se usó para almacenar la imagen. Para Artifact Registry, el formato de <image> es <region>-docker.pkg.dev/<project ID>/<repository name>/<image name>:<image tag>.

Para este lab, usamos la imagen pública openjdk:11.0-jdk. Agrega la siguiente línea a tu Dockerfile.

FROM openjdk:11.0-jdk

Configura el directorio de trabajo

La instrucción WORKDIR configura el directorio de trabajo para cualquier instrucción secuencial que siga en el Dockerfile. Para obtener más información, consulta la sección WORKDIR de la documentación de referencia de Dockerfile.

Sintaxis: WORKDIR <path>

Para este lab, usaremos el directorio /app como WORKDIR. Agrega la siguiente línea al final del Dockerfile.

WORKDIR /app

Copia los archivos de la aplicación

La instrucción COPY copia directorios o archivos de la ubicación <source> en la ruta <destination> del sistema de archivos de imágenes. Se pueden especificar varios recursos <source>, y todos están relacionados con el contexto de compilación. El contexto de compilación se analizará con más detalle en la sección Compilación. Para obtener más información, consulta la sección COPIA de la documentación de referencia de Dockerfile.

Sintaxis: COPY <source>... <destination>

Para este lab, copiaremos todos los archivos del repositorio en el sistema de archivos de imágenes. Agregue la siguiente línea al final de su Dockerfile

COPY . /app

Compila la aplicación

La instrucción RUN ejecuta comandos en una nueva capa de imagen sobre la imagen actual y confirma los resultados. La imagen confirmada resultante se usará para los pasos secuenciales en el Dockerfile. Para obtener más información, consulta la sección EJECUTAR de la documentación de referencia de Dockerfile.

Sintaxis: RUN <command>

En este lab, usaremos Maven para compilar la aplicación en un archivo JAR. Para ello, agregaremos la siguiente línea al final de tu Dockerfile

RUN ./mvnw compile assembly:single

Inicia la aplicación

La instrucción CMD proporciona el comando predeterminado para un contenedor en ejecución. Solo puede haber una instrucción de CMD en un Dockerfile. Si se especifica más de un CMD, solo se aplicará el último CMD. Hay funciones más avanzadas disponibles con las instrucciones de CMD y ENTRYPOINT, pero eso no se aborda en este lab. Para obtener más información, consulta la sección CMD de la documentación de referencia de Dockerfile.

Sintaxis: CMD ["executable","param1","param2"]

Para este lab, ejecutamos el archivo JAR que compilamos. Agrega la siguiente línea al final de tu Dockerfile

CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

Dockerfile final

El último Dockerfile se

FROM openjdk:11.0-jdk
WORKDIR /app
COPY . /app
RUN ./mvnw compile assembly:single
CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

Confirma el Dockerfile de manera local

cd ${HOME}/sample-app
git add Dockerfile
git commit -m "Added Dockerfile"

4. Compilación

Ahora, compilaremos la imagen desde el Dockerfile con el comando docker build. Este comando le indica al daemon de Docker que compile la imagen con las instrucciones de nuestro Dockerfile. Consulta la documentación de referencia de compilación de Docker para obtener más información.

Compila la imagen

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker build --tag sample-app:${IMAGE_TAG} .

Salida

Sending build context to Docker daemon  221.2kB
Step 1/4 : FROM openjdk:11.0-jdk
11.0-jdk: Pulling from library/openjdk
0c6b8ff8c37e: Pull complete
412caad352a3: Pull complete
e6d3e61f7a50: Pull complete
461bb1d8c517: Pull complete
e442ee9d8dd9: Pull complete
542c9fe4a7ba: Pull complete
41de18d1833d: Pull complete
Digest: sha256:d72b1b9e94e07278649d91c635e34737ae8f181c191b771bde6816f9bb4bd08a
Status: Downloaded newer image for openjdk:11.0-jdk
---> 2924126f1829
Step 2/4 : WORKDIR /app
---> Running in ea037abb273d
Removing intermediate container ea037abb273d
---> bd9b6d078082
Step 3/4 : COPY . /app
---> b9aec2b5de51
Step 4/4 : RUN ./mvnw compile jar:jar
---> Running in 3f5ff737b7fd
[INFO] Scanning for projects...
...
[INFO] Building jar: /app/target/sample-app-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  22.952 s
[INFO] Finished at: 2022-02-23T18:09:08Z
[INFO] ------------------------------------------------------------------------
Removing intermediate container 331443caebd3
---> 152f65cc441e
Step 5/5 : CMD ["java", "-jar", "/app/target/sample-app-1.0.0.jar"]
---> Running in 3d595a72231c
Removing intermediate container 3d595a72231c
---> 0e40d7548cab
Successfully built 0e40d7548cab
Successfully tagged sample-app:aaa8895

5. Ejecutar

Después de compilar correctamente la imagen de contenedor, podemos ejecutar la aplicación y asegurarnos de que se comporte como se espera con el comando docker run. Este comando iniciará el contenedor en primer plano en el símbolo del sistema para pruebas o depuración. Consulta la documentación de referencia de la ejecución de Docker para obtener más información.

Ejecuta un contenedor con la imagen

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG}

Salida

Listening at http://localhost:8080

Obtén una vista previa de la aplicación que se ejecuta en un contenedor

  • Haz clic en el botón Vista previa en la Web de Cloud Shell
  • Haz clic en Vista previa en el puerto 8080
  • Presiona CTRL + c en Cloud Shell para detener los contenedores

Cambia el comportamiento de los contenedores

Cuando se ejecuta Docker Run, se usa la configuración predeterminada en el Dockerfile. Se pueden agregar instrucciones y parámetros adicionales para modificar este comportamiento.

Habilitar el registro de TRACE

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG} \
  java -Dorg.slf4j.simpleLogger.defaultLogLevel=trace -jar /app/target/sample-app-1.0.0-jar-with-dependencies.jar

Obtén una vista previa de la aplicación que se ejecuta en un contenedor

  • Haz clic en el botón Vista previa en la Web de Cloud Shell
  • Haz clic en Vista previa en el puerto 8080
  • Cambia a la pestaña de Cloud Shell para ver el registro adicional
  • Presiona CTRL + c en Cloud Shell para detener el contenedor

Cambiar puerto

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
--rm \
-e PORT=8081 \
-p 8081:8081 \
sample-app:${IMAGE_TAG}

Obtén una vista previa de la aplicación que se ejecuta en un contenedor

  • Haz clic en el botón Vista previa en la Web de Cloud Shell
  • Haz clic en Cambiar puerto.
  • Ingresar 8081
  • Haz clic en Cambiar y obtener vista previa.
  • Presiona CTRL + c en Cloud Shell para detener el contenedor

6. Envío

Una vez que estamos seguros de que la imagen del contenedor se está ejecutando correctamente y queremos que este contenedor esté disponible para que se ejecute en otros entornos o que otros usuarios lo ejecuten, debemos enviar la imagen a un repositorio compartido. Esto debería ocurrir como parte de una canalización de compilación automatizada, pero en nuestro entorno de pruebas ya tenemos un repositorio configurado y podemos enviar la imagen de forma manual.

Envía la confirmación de Dockerfile al repositorio sample-app

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
git push

Etiqueta la imagen para Artifact Registry

docker tag sample-app:${IMAGE_TAG} \
    us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

Configura tus credenciales para Artifact Registry

gcloud auth configure-docker us-central1-docker.pkg.dev

Cuando se te solicite Do you want to continue (Y/n)?, responde y y presiona Enter

Envía la imagen a Artifact Registry

docker push us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

Salida

 The push refers to repository [us-central1-docker.pkg.dev/qwiklabs-gcp-04-b47ced695a3c/apps/sample-app]
  453b97f86449: Pushed
  e86791aa0382: Pushed
  d404c7ee0850: Pushed
  fe4f44af763d: Pushed
  7c072cee6a29: Pushed
  1e5fdc3d671c: Pushed
  613ab28cf833: Pushed
  bed676ceab7a: Pushed
  6398d5cccd2c: Pushed
  0b0f2f2f5279: Pushed
  aaa8895: digest: sha256:459de00f86f159cc63f98687f7c9563fd65a2eb9bcc71c23dda3351baf13607a size: 2424

7. ¡Felicitaciones!

¡Felicitaciones! Completaste el codelab.

Temas abordados

  • Crear un Dockerfile para una aplicación de muestra
  • Compila una imagen
  • Ejecutaste la imagen como un contenedor de manera local
  • Cambio en el comportamiento del contenedor
  • Se envió la imagen a Artifact Registry