为你的扩展程序添加后端服务

您的扩展可以附带一个后端部分,供前端与其交互。本页面提供有关为何以及如何添加后端的信息。

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

提示

请查看 快速入门指南docker extension init <my-extension>。它们为您的扩展提供了更佳的基础,因为其内容更加最新且与您安装的 Docker Desktop 相关。

为什么要添加后端?

得益于 Docker Extensions SDK,大多数情况下您都可以直接从 前端界面 通过 Docker CLI 完成所需操作。

尽管如此,在某些情况下,您可能需要为您的扩展程序添加后端。到目前为止,扩展程序开发者已利用后端来:

  • 将数据存储在本地数据库中,并通过 REST API 提供服务。
  • 存储扩展的状态,例如当一个按钮启动一个长时间运行的进程时,这样如果您离开扩展用户界面后再返回,前端可以从中断处继续执行。

有关扩展后端的更多信息,请参阅 架构

为扩展添加后端

如果你使用 docker extension init 命令创建了你的扩展,则已具备后端设置。否则,你需要先创建一个 vm 目录,其中包含代码,并更新 Dockerfile 以将其容器化。

这是带有后端的扩展文件夹结构:

.
├── Dockerfile # (1)
├── Makefile
├── metadata.json
├── ui
    └── index.html
└── vm # (2)
    ├── go.mod
    └── main.go
  1. 包含构建后端所需的一切,并将其复制到扩展的容器文件系统中。
  2. 包含扩展后端代码的源文件夹。

尽管您可以从空目录或 vm-ui extension 示例 开始, 但强烈建议您从 docker extension init 命令开始,并根据您的需求进行修改。

提示

docker extension init 会生成一个 Go 后端。但您仍可将其作为开发自身扩展的起点,并使用其他任意语言和框架,例如 Node.js、Python、Java、.NET 等。

在本教程中,后端服务仅暴露一个路由,该路由返回一个包含“Hello”消息的 JSON 负载。

{ "Message": "Hello" }

重要

我们建议,前端和后端应通过套接字(sockets)进行通信,在 Windows 上则使用命名管道(named pipes),而非 HTTP。这样可以避免与其他正在运行的应用程序或容器在主机上发生端口冲突。此外,部分 Docker Desktop 用户运行在受限环境中,无法在其机器上开放端口。在选择后端的语言和框架时,请确保其支持套接字连接。


package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/labstack/echo"
	"github.com/sirupsen/logrus"
)

func main() {
	var socketPath string
	flag.StringVar(&socketPath, "socket", "/run/guest/volumes-service.sock", "Unix domain socket to listen on")
	flag.Parse()

	os.RemoveAll(socketPath)

	logrus.New().Infof("Starting listening on %s\n", socketPath)
	router := echo.New()
	router.HideBanner = true

	startURL := ""

	ln, err := listen(socketPath)
	if err != nil {
		log.Fatal(err)
	}
	router.Listener = ln

	router.GET("/hello", hello)

	log.Fatal(router.Start(startURL))
}

func listen(path string) (net.Listener, error) {
	return net.Listen("unix", path)
}

func hello(ctx echo.Context) error {
	return ctx.JSON(http.StatusOK, HTTPMessageBody{Message: "hello world"})
}

type HTTPMessageBody struct {
	Message string
}

重要

我们尚未提供 Node.js 的可用示例。 填写表单 并告知我们您是否需要 Node.js 的示例。

重要

我们目前还没有 Python 的可用示例。 填写表单 并告知我们您是否需要 Python 示例。

重要

我们尚未提供 Java 的可用示例。 填写表单 并告知我们您是否需要 Java 示例。

重要

我们暂无适用于 .NET 的工作示例。 填写表单 并告知我们您是否需要 .NET 的示例。


调整 Dockerfile

注意

使用 docker extension init 时,会创建一个已包含 Go 后端所需内容的 Dockerfile


在安装扩展时部署您的 Go 后端,您需要先配置 Dockerfile,使其:

  • 构建后端应用程序
  • 将Binaries复制到扩展程序的容器文件系统中
  • 当容器在扩展套接字上开始监听时启动Binaries

提示

为简化版本管理,您可以重复使用同一镜像来构建前端、后端服务以及打包扩展。

# syntax=docker/dockerfile:1
FROM node:17.7-alpine3.14 AS client-builder
# ... build frontend application

# Build the Go backend
FROM golang:1.17-alpine AS builder
ENV CGO_ENABLED=0
WORKDIR /backend
COPY vm/go.* .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go mod download
COPY vm/. .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go build -trimpath -ldflags="-s -w" -o bin/service

FROM alpine:3.15
# ... add labels and copy the frontend application

COPY --from=builder /backend/bin/service /
CMD /service -socket /run/guest-services/extension-allthethings-extension.sock

重要

我们尚未提供适用于 Node.js 的可用 Dockerfile。 填写表单 并告知我们您是否需要 Node.js 的 Dockerfile。

重要

我们尚未提供可用的 Python Dockerfile。 填写表单 并告知我们您是否需要 Python 的 Dockerfile。

重要

我们尚未提供可用的 Java Dockerfile。 填写表单 并告知我们您是否需要 Java 的 Dockerfile。

重要

我们暂无适用于 .NET 的可用 Dockerfile。 填写表单 并告知我们您是否需要 .NET 的 Dockerfile。


配置元数据文件

要在 Docker Desktop 的虚拟机中启动您扩展的后端服务,您需要在 vm 文件的 metadata.json 部分中配置镜像名称。

{
  "vm": {
    "image": "${DESKTOP_PLUGIN_IMAGE}"
  },
  "icon": "docker.svg",
  "ui": {
    ...
  }
}

有关 vm 部分的 metadata.json 的更多信息,请参见 元数据

警告

请勿替换 metadata.json 文件中的 ${DESKTOP_PLUGIN_IMAGE} 占位符。安装扩展时,该占位符将被自动替换为正确的镜像名称。

从您的前端调用扩展后端

使用 高级前端扩展示例,我们可以调用我们的扩展后端。

使用 Docker Desktop Client 对象,然后从后端服务调用 /hello 路由,并通过 ddClient. extension.vm.service.get 获取响应的正文内容。


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


// ui/src/App.tsx
import React, { useEffect } from 'react';
import { createDockerDesktopClient } from "@docker/extension-api-client";

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

export function App() {
  const ddClient = createDockerDesktopClient();
  const [hello, setHello] = useState<string>();

  useEffect(() => {
    const getHello = async () => {
      const result = await ddClient.extension.vm?.service?.get('/hello');
      setHello(JSON.stringify(result));
    }
    getHello()
  }, []);

  return (
    <Typography>{hello}</Typography>
  );
}

重要

我们目前还没有 Vue 的示例。 填写表单 并告诉我们您是否希望我们提供一个 Vue 示例。

重要

我们暂无 Angular 的示例。 填写表单 并告知我们您是否希望提供 Angular 示例。

重要

我们尚未提供 Svelte 的示例。 填写表单 并告知我们您是否需要 Svelte 的示例。


重新构建扩展并更新它

由于您已修改扩展的配置并在 Dockerfile 中添加了构建阶段,因此必须重新构建该扩展。

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

构建完成后,您需要更新它,或者如果尚未安装,则需先进行安装。

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

现在您可以在 Docker Desktop 仪表板的 容器 视图中看到后端服务正在运行,并在需要调试时查看其日志。

提示

您可能需要在设置中启用显示系统容器选项,才能看到后端容器正在运行。 有关更多信息,请参见 显示扩展容器

打开 Docker Desktop 仪表板并选择 容器 标签页。您应能看到后端服务调用的响应内容。

接下来是什么?