Skip to main content

Administrar imágenes Docker de Node.js en GitHub Packages con GitHub Actions

Escrito por
blog hero github actions docker push

13 de julio de 2021

0 minutos de lectura

Si hoy desarrollas software de código abierto, es muy probable que participes en la comunidad de GitHub: colaboras en proyectos de código abierto y sus repositorios. Una incorporación reciente al ecosistema de GitHub es GitHub Packages, que se anunció en 2019 y ahora recibe aún más actualizaciones con la disponibilidad general del registro de contenedores de GitHub Packages. Esto significa que podemos publicar y descargar imágenes basadas en Docker, así como cualquier otro formato compatible con OCI, por completo dentro del ecosistema de GitHub.

En esta publicación, te guiaré paso a paso por un flujo de trabajo de GitHub Actions. Aprenderás a publicar proyectos de Node.js como imágenes Docker y luego subirlas al registro de contenedores GitHub Packages.

Antes de empezar, ¿sabías que hay un foro de soporte dedicado a los usuarios de GitHub, conocido como GitHub Support Community? Vale la pena visitarlo si necesitas ayuda con algo.

El proyecto de Node.js que usaremos en este artículo será dockly, una herramienta de línea de comandos de código abierto para Node.js que ofrece una interfaz de terminal envolvente para administrar contenedores y servicios Docker.

README de Dockly que muestra una interfaz de terminal para administrar contenedores de Docker, con listas de contenedores, gráficos de estado y registros.

Crear un flujo de trabajo de GitHub Actions

Ve a tu repositorio de código abierto en GitHub, haz clic en la pestaña Actions, luego en New Workflow y después en set up a workflow yourself. Deberías ver algo como esto:

Página de GitHub Actions que muestra el encabezado «Elige una plantilla de flujo de trabajo» y opciones para seleccionar o configurar un flujo de trabajo

Primero, definimos el nombre del archivo del flujo de trabajo y lo establecemos como docker-publish.yml o con cualquier otra convención de nombres que prefieras.

Es posible que GitHub complete previamente el código del flujo de trabajo. En ese caso, solo bórralo y pega lo siguiente:

name: Docker

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

on:
  push:
    branches: [ main ]
    tags: [ 'v*.*.*' ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

El flujo de trabajo anterior establece las siguientes convenciones:

  • El flujo de trabajo solo se ejecuta cuando se hacen commits en la rama main o se crean pull requests hacia la rama main. Nota: Si tu repositorio todavía usa la convención anterior de la rama master, cámbiala aquí y en el resto del fragmento de código. También se ejecuta cuando se suben etiquetas al repositorio con el formato semver <v*.*.*>, lo cual es útil porque así podemos publicar imágenes Docker para cada versión.

  • Se asegura de que, cuando se publique una nueva imagen Docker, también se creen etiquetas en el repositorio de GitHub.

  • Configura variables de entorno globales para el resto de los trabajos del flujo de trabajo. Estas apuntan a GitHub Container Registry (ghcr.io) y establecen el nombre de la imagen Docker mediante convenciones estándar, como las de Docker Hub: <user>/<repo>, por ejemplo, lirantal/nodejs-app.

A continuación, definiremos nuestros trabajos y estableceremos un proceso para crear la imagen Docker y luego publicarla.

Crear una imagen Docker como parte del flujo de trabajo de GitHub Actions

Para poder publicar imágenes Docker en el registro de contenedores GitHub Packages (o incluso solo en GitHub), primero debemos autenticarnos con una cuenta válida. Por eso, los primeros pasos del trabajo de creación y publicación consisten en iniciar sesión.

Copia el siguiente código a continuación del código anterior:

jobs:
  build_and_publish:

    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Log into registry ${{ env.REGISTRY }}
        if: github.event_name != 'pull_request'
        uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

Revisemos las acciones que realizan los trabajos descritos aquí:

  1. El primer paso es extraer el código fuente del repositorio.

  2. Luego, nos autenticamos en el registro de contenedores GitHub Packages. Como puedes ver, reutilizamos la variable de entorno REGISTRY que definimos antes, que apunta a ghcr.io, el registro propio de GitHub para imágenes de contenedores.

    El nombre de usuario para la autenticación es el de la persona que inició el flujo de trabajo, que debería coincidir con tu usuario, como propietario del repositorio. La contraseña usa GITHUB_TOKEN, que se pone automáticamente a disposición de los flujos de trabajo de GitHub Actions; no tienes que agregarlo manualmente como secreto ni como variable de entorno en el repositorio. Verás que el inicio de sesión en el registro no se realiza si se trata de un pull request, algo que de todos modos no es necesario y que podría exponer información confidencial en CI de pull requests y forks.

  3. El último paso del fragmento de código anterior ayuda a extraer metadatos de la imagen y ponerlos a disposición del proceso de creación de imágenes Docker (¡nuestro siguiente y último paso en este flujo de trabajo!). Los metadatos incluyen información sobre las etiquetas y los rótulos que se ponen a disposición de la acción de creación de Docker. En concreto, la entrada images define la imagen Docker que se usará como nombre base para las etiquetas.

Crear una imagen Docker y publicarla en el registro de contenedores GitHub Packages

El último paso es crear y publicar la imagen Docker. Esto se hace en un único paso que usa una acción compatible. Sin embargo, verás que establecemos la entrada pushde ese flujo de trabajo con una condición que solo intenta publicar la imagen en el registro si el evento no se activa por un pull request:

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

¡Eso es todo!

Una vez que guardes el flujo de trabajo (¡con la indentación correcta!) y lo actives al fusionarlo con la rama main, debería crear y publicar una imagen en el registro de contenedores GitHub Packages.

Si todo salió bien, deberías ver la esperada marca verde que indica que el trabajo se completó correctamente, como en mi caso:

Flujo de trabajo de GitHub Actions que muestra la compilación y el envío exitosos de una imagen a GHCR en la rama master

¿Cómo subo una imagen Docker al registro de contenedores GitHub Packages?

Usa la acción oficial de Docker para GitHub docker/build-push-action en el archivo de flujo de trabajo de GitHub Actions y asegúrate de que haya una variable de entorno REGISTRY establecida en ghcr.io.

Descargar imágenes Docker del registro de contenedores GitHub Packages

Ahora que nuestro proyecto tiene una imagen Docker publicada en un registro público, probémosla descargándola desde nuestro entorno de desarrollo local:

$ docker pull ghcr.io/lirantal/my-nodejs-app
Using default tag: latest
latest: Pulling from lirantal/my-nodejs-app
b4d181a07f80: Pulling fs layer
de8ecf497b75: Pulling fs layer
69b92f9e5e70: Pulling fs layer
1f2b8e2c8ad8: Waiting
d0f4259cb643: Waiting
9ae47f3f99ba: Waiting
87270829eb60: Waiting
905fc634546c: Waiting

¿Cómo especifico qué versión de una imagen Docker descargar?

El comando docker pull acepta un argumento adicional con el formato <registry>/<user>/<repo>:<image tag>. Por ejemplo, para descargar la etiqueta "latest" de la imagen Docker my-nodejs-app image del registro de contenedores GitHub Packages, usa el siguiente comando: docker pull ghcr.io/lirantal/my-nodejs-app

¡Genial, funcionó!

Pero espera... ¿no hay una mejor forma de ver las imágenes Docker que subo a GitHub Packages? ¡No busques más!

Encontrar imágenes Docker en GitHub Packages

Si visitas tu perfil de GitHub (por ejemplo, el mío: https://github.com/lirantal?tab=packages), ahora verás todas tus imágenes Docker públicas.

Si seguiste este tutorial para crear tu propia imagen Docker, ¿puedes encontrarla? Esta es la página del paquete de imagen Docker que subí a GitHub Packages como parte de la integración continua de GitHub Actions del repositorio:

Página de GitHub Container Registry para dockly, que muestra el comando para descargar la imagen de Docker, las versiones etiquetadas de la imagen y el archivo README.

¿No aparece la etiqueta latest en la imagen Docker publicada?

Si intentaste descargar la imagen Docker por su nombre, sin especificar la etiqueta de la imagen Docker para la rama main o master que usas, quizá hayas visto que la etiqueta de imagen Docker de uso común latest no está disponible. Esto ocurre si no se subieron etiquetas semver (versionado semántico). Si estás subiéndolas en tu propio repositorio, la etiqueta estará disponible.

Si queremos aplicar un alias de etiqueta latest a la imagen Docker publicada, podemos actualizar la acción de metadatos de la siguiente manera (observa la clave flavor adicional, que ocupa varias líneas):

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: |
            latest=true
            prefix=
            suffix=

Sin embargo, ten en cuenta que esto siempre hará que se establezca una etiqueta de imagen latest como alias de la imagen Docker que se publique cuando la rama main active un trabajo de CI.

¿Cómo etiqueto una imagen Docker como latest?

Para etiquetar localmente una imagen creada previamente, podemos usar esta estructura del comando docker tag: docker tag <local image name> <new tag>. Por ejemplo: docker tag my-nodejs-app lirantal/my-nodejs-app:latest

¿Cómo ejecuto una imagen Docker con una etiqueta?

Para usar una etiqueta específica de una imagen Docker al ejecutarla, solo tienes que proporcionar el nombre completo de la imagen y la etiqueta al comando docker run. Por ejemplo: docker run --rm -p 27017:27017 mongo:latest

Integraciones relacionadas con Docker y contenedores en GitHub Actions Marketplace

Otra forma de encontrar y crear flujos de trabajo de GitHub Actions es en GitHub Actions Marketplace, que ofrece más de 9000 flujos de trabajo para usar en calidad de código, administración de dependencias, seguridad y mucho más. También encontrarás Snyk GitHub Actions, que te ayudan a proteger tus proyectos contra vulnerabilidades de terceros en bibliotecas de código abierto y a asegurar que tu equipo siga prácticas de codificación segura.

Para lo que nos ocupa en este artículo —crear, probar y publicar imágenes Docker en un registro—, hay una forma más sencilla de empezar que explorar el marketplace. Si ya tienes un Dockerfile en tu repositorio, GitHub lo detectará automáticamente y te sugerirá flujos de trabajo relevantes para GitHub Actions. Solo ve a la pestaña Actions:

Página de configuración de GitHub Actions que muestra flujos de trabajo sugeridos de Dockerfile para publicar un contenedor Docker o crear una imagen de Docker

El primer flujo de trabajo sugerido, Publish Docker Container, te permitirá configurar un flujo de trabajo similar para crear y publicar imágenes Docker al que ya vimos.

Resumen y próximos pasos

¿Te interesan un poco más las prácticas de desarrollo seguro? ¡Excelente! Aquí tienes algunos recursos de lectura para empezar y sumar puntos de seguridad con tu equipo:

  1. La seguridad de la cadena de suministro es importante. Aquí tienes 10 buenas prácticas de seguridad para GitHub para asegurarte de no repetir errores.

  2. ¿Te interesa Node.js y crear paquetes npm? ¡A mí también! Escribí un artículo para ayudarte a empezar con GitHub Actions para publicar paquetes npm de forma segura.

  3. Si pasas mucho tiempo en el ecosistema de GitHub, conoce el análisis de código de Snyk, que ofrece una experiencia más integrada en tus flujos de trabajo: Análisis de código de seguridad de GitHub: protege tus dependencias de código abierto

Empieza con los retos de Capture the Flag

Aprende a resolver retos de Capture the Flag viendo nuestro taller virtual de nivel básico a pedido.

Publicado en: