Compartir comentarios
Las respuestas se generan en base a la documentación.

Crear una extensión frontend avanzada

Para comenzar a crear tu extensión, primero necesitas un directorio con archivos que van desde el código fuente de la extensión hasta los archivos específicos requeridos para la misma. Esta página proporciona información sobre cómo configurar una extensión con un frontend más avanzado.

Antes de comenzar, asegúrate de tener instalada la última versión de Docker Desktop.

Estructura de carpetas de la extensión

La forma más rápida de crear una nueva extensión es ejecutar docker extension init mi-extension como se describe en la Guía de inicio rápido. Esto crea un nuevo directorio mi-extension que contiene una extensión completamente funcional.

Tip

El comando docker extension init genera una extensión basada en React. Sin embargo, puedes usarlo como punto de partida para tu propia extensión y utilizar cualquier otro framework de frontend, como Vue, Angular, Svelte, etc., o incluso quedarte con JavaScript puro.

Aunque puedes comenzar desde un directorio vacío o desde la carpeta de ejemplos de react-extension, se recomienda encarecidamente que comiences con el comando docker extension init y lo modifiques según tus necesidades.

.
├── Dockerfile # (1)
├── ui # (2)
│   ├── public # (3)
│   │   └── index.html
│   ├── src # (4)
│   │   ├── App.tsx
│   │   ├── index.tsx
│   ├── package.json
│   └── package-lock.lock
│   ├── tsconfig.json
├── docker.svg # (5)
└── metadata.json # (6)
  1. Contiene todo lo necesario para compilar la extensión y ejecutarla en Docker Desktop.
  2. Carpeta de alto nivel que contiene el código fuente de tu aplicación frontend.
  3. Los recursos que no se compilan ni se generan dinámicamente se almacenan aquí. Pueden ser recursos estáticos como logotipos o el archivo robots.txt.
  4. La carpeta src, o carpeta de origen, contiene todos los componentes de React, archivos CSS externos y recursos dinámicos que se importan a los archivos de los componentes.
  5. El icono que se muestra en el menú izquierdo del panel de control (Dashboard) de Docker Desktop.
  6. Un archivo que proporciona información sobre la extensión, como el nombre, la descripción y la versión.

Adaptar el Dockerfile

Note

Al utilizar docker extension init, este crea un Dockerfile que ya contiene lo necesario para una extensión de React.

Una vez creada la extensión, debes configurar el Dockerfile para compilar la extensión y definir las etiquetas (labels) que se utilizan para rellenar la ficha de la extensión en el Marketplace. Aquí tienes un ejemplo de un Dockerfile para una extensión de React:

# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM node:18.9-alpine3.15 AS client-builder
WORKDIR /ui
# almacenar paquetes en caché en la capa
COPY ui/package.json /ui/package.json
COPY ui/package-lock.json /ui/package-lock.json
RUN --mount=type=cache,target=/usr/src/app/.npm \
    npm set cache /usr/src/app/.npm && \
    npm ci
# instalar
COPY ui /ui
RUN npm run build

FROM alpine
LABEL org.opencontainers.image.title="My extension" \
    org.opencontainers.image.description="Your Desktop Extension Description" \
    org.opencontainers.image.vendor="Awesome Inc." \
    com.docker.desktop.extension.api.version="0.3.3" \
    com.docker.desktop.extension.icon="https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png" \
    com.docker.extension.screenshots="" \
    com.docker.extension.detailed-description="" \
    com.docker.extension.publisher-url="" \
    com.docker.extension.additional-urls="" \
    com.docker.extension.changelog=""

COPY metadata.json .
COPY docker.svg .
COPY --from=client-builder /ui/build ui

Nota

En el ejemplo del Dockerfile, puedes ver que la etiqueta de imagen com.docker.desktop.extension.icon está configurada con la URL de un icono. El Marketplace de extensiones muestra este icono sin instalar la extensión. El Dockerfile también incluye COPY docker.svg . para copiar un archivo de icono dentro de la imagen. Este segundo archivo de icono se utiliza para mostrar la UI de la extensión en el Dashboard una vez que la extensión está instalada.

Important

Aún no tenemos un Dockerfile funcional para Vue. Completa el formulario y haznos saber si te gustaría ver un Dockerfile para Vue.

Important

Aún no tenemos un Dockerfile funcional para Angular. Completa el formulario y haznos saber si te gustaría ver un Dockerfile para Angular.

Important

Aún no tenemos un Dockerfile funcional para Svelte. Completa el formulario y haznos saber si te gustaría ver un Dockerfile para Svelte.

Configurar el archivo de metadatos

Para añadir una pestaña en Docker Desktop para tu extensión, debes configurarla en el archivo metadata.json en la raíz del directorio de tu extensión.

{
  "icon": "docker.svg",
  "ui": {
    "dashboard-tab": {
      "title": "UI Extension",
      "root": "/ui",
      "src": "index.html"
    }
  }
}

La propiedad title es el nombre de la extensión que se muestra en el menú izquierdo del panel de control de Docker Desktop. La propiedad root es la ruta a la aplicación frontend en el sistema de archivos del contenedor de la extensión, utilizada por el sistema para desplegarla en el host. La propiedad src es la ruta al punto de entrada HTML de la aplicación frontend dentro de la carpeta root.

Para obtener más información sobre la sección ui del metadata.json, consulta Metadatos.

Compilar la extensión e instalarla

Ahora que has configurado la extensión, debes compilar la imagen de la extensión que utilizará Docker Desktop para instalarla.

docker build --tag=awesome-inc/my-extension:latest .

Esto compilará una imagen etiquetada como awesome-inc/my-extension:latest. Puedes ejecutar docker inspect awesome-inc/my-extension:latest para ver más detalles al respecto.

Por último, puedes instalar la extensión y ver cómo aparece en el panel de control de Docker Desktop.

docker extension install awesome-inc/my-extension:latest

Utilizar el cliente de las APIs de la extensión

Para utilizar las APIs de la extensión y realizar acciones con Docker Desktop, la extensión debe importar primero la biblioteca @docker/extension-api-client. Para instalarla, ejecuta el siguiente comando:

npm install @docker/extension-api-client

Luego, llama a la función createDockerDesktopClient para crear un objeto cliente con el fin de invocar las APIs de la extensión.

import { createDockerDesktopClient } from "@docker/extension-api-client";

const ddClient = createDockerDesktopClient();

Si utilizas TypeScript, también puedes instalar @docker/extension-api-client-types como una dependencia de desarrollo. Esto te proporcionará definiciones de tipo para las APIs de la extensión y autocompletado en tu IDE.

npm install @docker/extension-api-client-types --save-dev
Autocompletado en un IDE

Por ejemplo, puedes utilizar la función docker.cli.exec para obtener la lista de todos los contenedores mediante el comando docker ps --all y mostrar el resultado en una tabla.

Reemplaza el archivo ui/src/App.tsx con el siguiente código:

// ui/src/App.tsx
import React, { useEffect } from "react";
import {
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Typography,
} from "@mui/material";
import { createDockerDesktopClient } from "@docker/extension-api-client";

// obtener el cliente de la extensión de Docker Desktop
const ddClient = createDockerDesktopClient();

export function App() {
  const [containers, setContainers] = React.useState<any[]>([]);

  useEffect(() => {
    // Listar todos los contenedores
    ddClient.docker.cli
      .exec("ps", ["--all", "--format", '"{{json .}}"'])
      .then((result) => {
        // result.parseJsonLines() analiza la salida del comando en un array de objetos
        setContainers(result.parseJsonLines());
      });
  }, []);

  return (
    <Stack>
      <Typography data-testid="heading" variant="h3" role="title">
        Container list
      </Typography>
      <Typography
        data-testid="subheading"
        variant="body1"
        color="text.secondary"
        sx={{ mt: 2 }}
      >
        Simple list of containers using Docker Extensions SDK.
      </Typography>
      <TableContainer sx={{ mt: 2 }}>
        <Table>
          <TableHead>
            <TableRow>
              <TableCell>Container id</TableCell>
              <TableCell>Image</TableCell>
              <TableCell>Command</TableCell>
              <TableCell>Created</TableCell>
              <TableCell>Status</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {containers.map((container) => (
              <TableRow
                key={container.ID}
                sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
              >
                <TableCell>{container.ID}</TableCell>
                <TableCell>{container.Image}</TableCell>
                <TableCell>{container.Command}</TableCell>
                <TableCell>{container.CreatedAt}</TableCell>
                <TableCell>{container.Status}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    </Stack>
  );
}
Captura de pantalla de la lista de contenedores.
Important

Aún no tenemos un ejemplo para Vue. Completa el formulario y haznos saber si te gustaría ver un ejemplo con Vue.

Important

Aún no tenemos un ejemplo para Angular. Completa el formulario y haznos saber si te gustaría ver un ejemplo con Angular.

Important

Aún no tenemos un ejemplo para Svelte. Completa el formulario y haznos saber si te gustaría ver un ejemplo con Svelte.

Políticas aplicadas al código del frontend

El código de la UI de la extensión se renderiza en una sesión de Electron separada y no tiene un entorno de Node.js inicializado, ni acceso directo a las APIs de Electron.

Esto se hace para limitar los posibles efectos secundarios inesperados en el panel de control general de Docker.

El código de la UI de la extensión no puede realizar tareas privilegiadas, como realizar cambios en el sistema o generar subprocesos, excepto mediante el uso de las APIs del SDK provistas con el framework de extensiones. El código de la UI de la extensión también puede realizar interacciones con Docker Desktop, como navegar a varios lugares en el Dashboard, únicamente a través de las APIs del SDK de la extensión.

Las partes de la UI de las extensiones están aisladas entre sí y el código de la UI de la extensión se ejecuta en su propia sesión para cada extensión. Las extensiones no pueden acceder a los datos de sesión de otras extensiones.

localStorage es uno de los mecanismos del almacenamiento web de un navegador. Permite a los usuarios guardar datos como pares clave-valor en el navegador para su uso posterior. localStorage no borra los datos cuando el navegador (el panel de la extensión) se cierra. Esto lo hace ideal para persistir datos al navegar fuera de la extensión hacia otras partes de Docker Desktop.

Si tu extensión utiliza localStorage para almacenar datos, otras extensiones que se ejecuten en Docker Desktop no podrán acceder al almacenamiento local de tu extensión. El almacenamiento local de la extensión persiste incluso después de que Docker Desktop se detenga o reinicie. Cuando se actualiza una extensión, su almacenamiento local se conserva, mientras que cuando se desinstala, su almacenamiento local se elimina por completo.

Recompilar la extensión y actualizarla

Dado que has modificado el código de la extensión, debes compilar la extensión de nuevo.

$ docker build --tag=awesome-inc/my-extension:latest .

Una vez compilada, debes actualizarla.

$ docker extension update awesome-inc/my-extension:latest

Ahora puedes ver el servicio de backend ejecutándose en la pestaña de contenedores del panel de control de Docker Desktop y revisar los registros (logs) cuando necesites depurarlo.

Tip

Puedes activar la recarga en caliente (hot reloading) para evitar la necesidad de recompilar la extensión cada vez que realices un cambio.

¿Qué sigue?