创建高级前端扩展

要开始创建扩展,您首先需要一个目录,其中包含从扩展源代码到所需的扩展特定文件的文件。本页提供了有关如何使用更高级的前端设置扩展的信息。

在开始之前,请确保您已安装最新版本的 Docker Desktop

扩展文件夹结构

创建新扩展的最快方法是按照快速入门中的方式运行。这将创建一个包含功能齐全的扩展的新目录。docker extension init my-extensionmy-extension

提示

这会生成一个基于 React 的扩展。但您仍然可以将其用作 您自己的扩展并使用任何其他前端框架,如 Vue、Angular、Svelte 等,甚至继续使用 原版 Javascript。docker extension init

尽管您可以从空目录或示例文件夹开始, 强烈建议您从命令开始,然后根据需要进行更改。react-extensiondocker extension init

.
├── 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. 包含构建扩展并在 Docker Desktop 中运行扩展所需的一切。
  2. 包含前端应用程序源代码的 High-level 文件夹。
  3. 未编译或动态生成的资产将存储在此处。这些可以是静态资源,如 logo 或 robots.txt 文件。
  4. src 或 source 文件夹包含引入组件文件的所有 React 组件、外部 CSS 文件和动态资源。
  5. 显示在 Docker Desktop Dashboard 左侧菜单中的图标。
  6. 提供有关扩展名的信息(如名称、描述和版本)的文件。

适配 Dockerfile

注意

当使用 时,它会创建一个已经包含 React 所需内容 外延。docker extension initDockerfile

创建扩展后,您需要配置 以构建扩展并配置标签 用于在 Marketplace 中填充扩展的卡。下面是一个 React 的 a 示例 外延:DockerfileDockerfile


# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM node:18.9-alpine3.15 AS client-builder
WORKDIR /ui
# cache packages in layer
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
# install
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

注意

在示例 Dockerfile 中,您可以看到镜像标签设置为图标 URL。Extensions Marketplace 显示此图标,但不安装扩展。Dockerfile 还包括在镜像中复制图标文件的功能。安装扩展后,第二个图标文件用于在 Dashboard 中显示扩展 UI。com.docker.desktop.extension.iconCOPY docker.svg .

重要

我们还没有适用于 Vue 的 Dockerfile。填写表格告诉我们您是否需要适用于 Vue 的 Dockerfile。

重要

我们还没有适用于 Angular 的 Dockerfile。填写表格告诉我们您是否需要适用于 Angular 的 Dockerfile。

重要

我们还没有适用于 Svelte 的 Dockerfile。填写表单告诉我们您是否需要适用于 Svelte 的 Dockerfile。


配置元数据文件

为了在 Docker Desktop 中为您的扩展添加选项卡,您必须在扩展目录的根目录中对其进行配置。metadata.json

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

该属性是显示在 Docker Desktop Dashboard 的左侧菜单中的扩展的名称。 该属性是 系统将其部署到主机上。 该属性是文件夹中前端应用程序的 HTML 入口点的路径。titlerootsrcroot

有关 部分的更多信息,请参阅 元数据.uimetadata.json

构建并安装扩展

现在,您已经配置了扩展,您需要构建 Docker Desktop 将用于的扩展镜像 安装它。

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

这构建了一个标记为 的镜像,您可以运行以查看有关它的更多详细信息。awesome-inc/my-extension:latestdocker inspect awesome-inc/my-extension:latest

最后,您可以安装该扩展,并看到它出现在 Docker Desktop Dashboard 中。

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

使用扩展 API 客户端

要使用扩展 API 并通过 Docker Desktop 执行操作,扩展必须先导入库。要安装它,请运行以下命令:@docker/extension-api-client

npm install @docker/extension-api-client

然后调用函数创建 client 对象,以调用扩展 API。createDockerDesktopClient

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

const ddClient = createDockerDesktopClient();

使用 Typescript 时,您还可以作为 dev 依赖项进行安装。这将 为您提供扩展 API 的类型定义和 IDE 中的自动完成功能。@docker/extension-api-client-types

npm install @docker/extension-api-client-types --save-dev
Auto completion in an IDE

例如,您可以使用该函数通过命令获取所有容器的列表,并将结果显示在表中。docker.cli.execdocker ps --all


将文件替换为以下代码:ui/src/App.tsx


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

//obtain docker desktop extension client
const ddClient = createDockerDesktopClient();

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

  useEffect(() => {
    // List all containers
    ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"']).then((result) => {
      // result.parseJsonLines() parses the output of the command into an array of objects
      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>
  );
}
Screenshot of the container list.

重要

我们还没有 Vue 的示例。填写表格告诉我们您是否需要 Vue 的示例。

重要

我们还没有 Angular 的示例。填写表格告诉我们您是否需要 Angular 的示例。

重要

我们还没有 Svelte 的示例。填写表格告诉我们您是否需要 Svelte 的样品。


为前端代码实施的策略

扩展 UI 代码在单独的 electron 会话中呈现,没有初始化 node.js 环境,也不直接访问 electron API。

这是为了限制整个 Docker Dashboard 可能出现的意外副作用。

扩展 UI 代码无法执行特权任务,例如更改系统或生成子进程,除非使用扩展框架提供的 SDK API。 扩展 UI 代码还可以执行与 Docker Desktop 的交互,例如仅通过扩展 SDK API 导航到 Dashboard 中的各个位置。

扩展 UI 部件彼此隔离,并且扩展 UI 代码在每个扩展的自己的会话中运行。扩展程序无法访问其他扩展程序的会话数据。

localStorage是浏览器的 Web 存储机制之一。它允许用户在浏览器中将数据保存为键值对以备后用。 在浏览器(扩展窗格)关闭时不清除数据。这使得它非常适合在从扩展导航到 Docker Desktop 的其他部分时保留数据。localStorage

如果您的扩展用于存储数据,则在 Docker Desktop 中运行的其他扩展无法访问您的扩展的本地存储。即使在 Docker Desktop 停止或重启后,扩展的本地存储也会保留。升级扩展时,将保留其本地存储,而卸载扩展时,将完全删除其本地存储。localStorage

重新构建扩展并更新

由于您已经修改了扩展的代码,因此必须重新构建扩展。

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

构建完成后,您需要更新它。

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

现在,您可以在 Docker Desktop Dashboard 的 containers 选项卡中看到正在运行的后端服务,并查看日志 当您需要调试它时。

提示

您可以开启热重载,以避免 每次进行更改时重新构建扩展。

下一步是什么?