확장에 백엔드 추가하기

확장에 백엔드 추가하기 (Add a backend to your extension)

Docker 확장에 백엔드(backend) 부분을 추가하고 프론트엔드에서 호출하는 방법을 설명하는 튜토리얼이에요.

출처: 문서

본문

확장은 프론트엔드가 상호작용할 수 있는 백엔드 부분과 함께 배포될 수 있어요. 이 페이지는 백엔드를 왜, 어떻게 추가하는지에 대한 정보를 제공해요.

시작하기 전에 최신 버전의 Docker Desktop을 설치했는지 확인하세요.

팁: Quickstart 가이드와 docker extension init <my-extension>을 확인하세요. 이것들은 Docker Desktop 설치와 관련되고 최신 상태이므로 더 나은 확장의 기반이 돼요.

왜 백엔드를 추가하나요?

Docker Extensions SDK 덕분에 대부분의 경우 Docker CLI에서 필요한 작업을 프론트엔드에서 직접 수행할 수 있어요.

그럼에도 확장에 백엔드를 추가해야 하는 경우가 있어요. 지금까지 확장 빌더들은 백엔드를 다음과 같은 용도로 사용했어요:

  • 로컬 데이터베이스에 데이터를 저장하고 REST API로 다시 제공
  • 확장 상태 저장 - 예를 들어 버튼이 장기 실행 프로세스를 시작할 때, 확장 사용자 인터페이스에서 벗어났다가 돌아와도 프론트엔드가 중단된 지점부터 이어받을 수 있게 함

확장 백엔드에 대한 자세한 내용은 Architecture를 참조하세요.

확장에 백엔드 추가하기

docker extension init 명령으로 확장을 만들었다면 이미 백엔드가 설정되어 있어요. 그렇지 않다면 먼저 코드를 포함하는 vm 디렉터리를 만들고 Dockerfile을 업데이트해 컨테이너화해야 해요.

백엔드가 있는 확장 폴더 구조:

.
├── Dockerfile # (1)
├── Makefile
├── metadata.json
├── ui
    └── index.html
└── vm # (2)
    ├── go.mod
    └── main.go
  • (1) 백엔드를 빌드하고 확장의 컨테이너 파일 시스템에 복사하는 데 필요한 모든 것을 포함해요.
  • (2) 확장의 백엔드 코드를 포함하는 소스 폴더예요.

빈 디렉터리나 vm-ui 확장 샘플에서 시작할 수도 있지만, docker extension init 명령에서 시작해 필요에 맞게 변경하는 것을 강력히 권장해요.

팁: docker extension init은 Go 백엔드를 생성해요. 하지만 이것을 시작점으로 사용하고 Node.js, Python, Java, .Net 또는 다른 언어와 프레임워크를 사용해도 돼요.

이 튜토리얼에서 백엔드 서비스는 단순히 "Hello"라고 말하는 JSON 페이로드를 반환하는 하나의 라우트를 노출해요.

{ "Message": "Hello" }

중요: 프론트엔드와 백엔드가 HTTP 대신 소켓과(Windows에서는 named pipes) 통신하는 것을 권장해요. 이렇게 하면 호스트에서 실행되는 다른 실행 중인 애플리케이션이나 컨테이너와의 포트 충돌을 방지할 수 있어요. 또한 일부 Docker Desktop 사용자는 머신에서 포트를 열 수 없는 제한된 환경에서 실행하고 있어요. 백엔드의 언어와 프레임워크를 선택할 때 소켓 연결을 지원하는지 확인하세요.

Go 백엔드 예시:

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을 사용하면 Go 백엔드에 필요한 것을 이미 포함한 Dockerfile을 생성해요.

Go 백엔드를 확장 설치 시 배포하려면 먼저 Dockerfile을 구성해서 다음을 수행하도록 해야 해요:

  1. 백엔드 애플리케이션 빌드
  2. 바이너리를 확장의 컨테이너 파일 시스템에 복사
  3. 컨테이너가 확장 소켓에서 수신을 시작할 때 바이너리 시작

팁: 버전 관리를 쉽게 하기 위해 동일한 이미지를 재사용해 프론트엔드를 빌드하고, 백엔드 서비스를 빌드하며, 확장을 패키징할 수 있어요.

# 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
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    --mount=type=bind,source=vm/.,target=. \
    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의 VM 안에서 시작하려면 metadata.json 파일의 vm 섹션에 이미지 이름을 구성해야 해요.

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

metadata.json의 vm 섹션에 대한 자세한 내용은 Metadata를 참조하세요.

경고: metadata.json 파일에서 ${DESKTOP_PLUGIN_IMAGE} 자리 표시자를 교체하지 마세요. 자리 표시자는 확장이 설치될 때 올바른 이미지 이름으로 자동 교체됩니다.

프론트엔드에서 확장 백엔드 호출하기

고급 프론트엔드 확장 예시를 사용해 확장 백엔드를 호출할 수 있어요.

Docker Desktop Client 객체를 사용하고 ddClient.extension.vm.service.get으로 백엔드 서비스의 /hello 라우트를 호출해 응답 본문을 반환받아요.

ui/src/App.tsx 파일을 다음 코드로 교체하세요:

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

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

export function App() {
  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의 Containers 보기에서 백엔드 서비스가 실행되는 것을 볼 수 있고, 디버그가 필요할 때 로그를 확인할 수 있어요.

팁: 백엔드 컨테이너가 실행되는 것을 보려면 Settings에서 Show system containers 옵션을 켜야 할 수 있어요. 확장 컨테이너 표시에 대한 자세한 내용을 참조하세요.

Docker Desktop Dashboard를 열고 Containers 탭을 선택하세요. 백엔드 서비스 호출의 응답이 표시되는 것을 볼 수 있어야 해요.

다음은 무엇인가요?

확장 공유 및 게시 방법을 알아보세요. 확장 아키텍처에 대해 자세히 알아보세요.

더 알아보기 (Learn more)