为你的扩展添加后端

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

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

提示

查看 快速入门指南docker extension init 。它们为您的扩展提供了更好的基础,因为它们更最新且与您安装的 Docker Desktop 相关。

为什么要添加后端?

感谢Docker扩展SDK,大多数时候你应该能够直接从前端完成你需要的操作。

尽管如此,在某些情况下,您可能需要在扩展中添加后端。到目前为止,扩展构建者已经使用后端来:

  • 将数据存储在本地数据库中,并通过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 或任何其他语言和框架。

在本教程中,后端服务仅公开一个返回JSON负载的路由,该负载显示“Hello”。

{ "Message": "Hello" }

重要

我们建议,前端和后端通过套接字进行通信,在Windows上使用命名管道,而不是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提供一个工作示例。 填写表格 并告诉我们你是否需要一个Node的示例。

重要

我们还没有一个Python的工作示例。 填写表格 并告诉我们你是否需要一个Python的示例。

重要

我们还没有Java的工作示例。 填写表格 并告诉我们你是否需要Java的示例。

重要

我们没有.NET的工作示例。 填写表格 并告诉我们是否需要.NET的示例。


调整Dockerfile

注意

当使用docker extension init时,它会创建一个Dockerfile,其中已经包含了Go后端所需的内容。


在安装扩展时部署您的Go后端,您首先需要配置Dockerfile,以便它:

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

提示

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

# 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的Dockerfile。 填写表格 并告诉我们你是否需要一个Node的Dockerfile。

重要

我们还没有一个可用的Python Dockerfile。 填写表格 并告诉我们你是否需要一个Python的Dockerfile。

重要

我们还没有一个可用的Java Dockerfile。 填写表格 并告诉我们你是否需要一个Java的Dockerfile。

重要

我们没有适用于 .Net 的 Dockerfile。 填写表格 并告诉我们是否需要 .Net 的 Dockerfile。


配置元数据文件

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

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

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

警告

不要替换${DESKTOP_PLUGIN_IMAGE}占位符在metadata.json文件中。当扩展安装时,占位符会自动替换为正确的镜像名称。

从前端调用扩展后端

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

使用Docker Desktop客户端对象,然后通过ddClient.extension.vm.service.get从后端服务调用/hello路由,该路由返回响应体。


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 Dashboard的容器视图中看到后端服务正在运行,并在需要调试时查看日志。

提示

您可能需要在设置中打开显示系统容器选项,以查看正在运行的后端容器。 更多信息请参见 显示扩展容器

打开Docker Desktop仪表板并选择容器标签。你应该能看到后端服务调用的响应显示出来。

接下来是什么?