2023年1月にリリースされた Docker Desktop v4.16.0 (release notes) で GA になった「Docker Extensions」の Extensions は段々と種類が増えてきて,Disk Usage / Aqua Trivy / LocalStack など,最近使う機会もあったりする.今回は "Quickstart" ドキュメントを読みながら Docker Extensions の実装に入門してみた❗️
\( 'ω')/ オレオレ Docker Extension を実装するぞー
🐳 docker extension
コマンド
まず,Docker Extensions を実装するためには docker extension
コマンドを使う.コマンド一覧を以下に載せておく.
$ docker extension --help Usage: docker extension [OPTIONS] COMMAND Manages Docker extensions Options: --socket string The Desktop extension manager socket Management Commands: dev Extension development helpers Commands: init Create a new Docker Extension based on a template. install Install a Docker extension with the specified image ls List installed Docker extensions rm Remove a Docker extension share Generate a link to share the extension. update Remove and re-install a Docker extension validate Validate an extension image or metadata file version Print the client and server versions Run 'docker extension COMMAND --help' for more information on a command. $ docker extension dev --help Usage: docker extension dev COMMAND Extension development helpers Commands: debug Set the debug mode for an extension reset Reset the source and disables the debug mode for the extension UI ui-source Set a new source for the extension UI Run 'docker extension dev COMMAND --help' for more information on a command.
🐳 検証環境
今回は Docker Desktop for Mac v4.16.2 と,以下の Docker Extensions を検証環境として使う.
$ docker extension version Client Version: v0.2.17 Server API Version: 0.3.3
🐳 docker extension init
コマンド
まず docker extension init
コマンドを実行すると Docker Extensions のプロジェクトを簡単にセットアップできる.Quickstart に沿って,今回は my-extension
という名前にする.初期化中のログを見ると Go backend や React app など,馴染みのある技術スタックが使われていることがわかる❗️
$ docker extension init my-extension ? Title: my-extension ? Description: my-extension ? Vendor: kakakakakku ? Image Repository where the extension will be pushed: kakakakakku/my-extension (中略) Creating a Go backend service... Initializing new go module... Creating a React app... Copying ui dir... Renaming some files... Installing npm packages, this may take a few minutes... (中略)
プロジェクトディレクトリは以下のようになる(tree
コマンドで2階層目まで表示している).
$ tree -L 2 . . ├── Dockerfile ├── Makefile ├── README.md ├── backend │ ├── go.mod │ ├── go.sum │ └── main.go ├── docker-compose.yaml ├── docker.svg ├── metadata.json └── ui ├── index.html ├── node_modules ├── package-lock.json ├── package.json ├── public ├── src ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts 6 directories, 15 files
Docker Extensions を実装する前に「構成」を理解しておく必要がある.Docker Extensions は,重要な2つのコンポーネント「UI (例: React x TypeScript x MUI)」と「Backend (例: Go)」を組み合わせて実装する❗️以下に UI (Frontend) と Backend の関係性がまとまった図をドキュメントから引用して載せておく.
ちなみに「UI」は React に限定されているわけではなく Vue / Anguler なども使える.「Backend」も Go に限定されているわけではなく Node.js / Python なども使える.よって,Docker Extensions を実装する技術スタックとしては「自由度がある」とも言える.詳しくはドキュメント参照〜
さらに React コンポーネントとしてデフォルトで導入されている「MUI(旧 Material UI)」も限定されているわけではなく,他のライブラリを使うこともできる.しかし,Docker Extensions のドキュメントには「React x MUI 推奨」と書いてある.Docker Extensions デザインの一貫性 (look & feel) の観点や今後 MUI を拡張する予定もあるらしく,基本的には MUI を使うのが良さそう.
🐳 Dockerfile
次に Dockerfile
を確認する.初期化したときに作られた Dockerfile
は以下のようになっていた.ポイントは Multi-stage builds を使って Backend (Go) と UI (React) をビルドして,最終的に Alpine イメージにまとめているところ.
FROM golang:1.19-alpine AS builder ENV CGO_ENABLED=0 WORKDIR /backend COPY backend/go.* . RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ go mod download COPY backend/. . 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 --platform=$BUILDPLATFORM node:18.12-alpine3.16 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="my-extension" \ org.opencontainers.image.vendor="kakakakakku" \ com.docker.desktop.extension.api.version="0.3.3" \ com.docker.extension.screenshots="" \ com.docker.extension.detailed-description="" \ com.docker.extension.publisher-url="" \ com.docker.extension.additional-urls="" \ com.docker.extension.changelog="" COPY --from=builder /backend/bin/service / COPY docker-compose.yaml . COPY metadata.json . COPY docker.svg . COPY --from=client-builder /ui/build ui CMD /service -socket /run/guest-services/backend.sock
🐳 コンテナイメージをビルドする
手順に戻る!今度は docker build
コマンドを実行して Dockerfile からコンテナイメージをビルドする.Multi-stage builds を使っているので,最終的に 12.6MB
とサイズも小さく抑えられている.
$ docker build -t kakakakakku/my-extension . $ docker image ls kakakakakku/my-extension REPOSITORY TAG IMAGE ID CREATED SIZE kakakakakku/my-extension latest ef80c4794f8b About a minute ago 12.6MB
🐳 docker extension install
コマンド
最後は docker extension install
コマンドを実行して Docker Extensions を Docker Desktop にインストールすれば完了〜
$ docker extension install kakakakakku/my-extension Extensions can install binaries, invoke commands and access files on your machine. Are you sure you want to continue? [y/N] y Installing new extension "kakakakakku/my-extension" Installing service in Desktop VM... Setting additional compose attributes VM service started Installing Desktop extension UI for tab "My-Extension"... Extension UI tab "My-Extension" added. Extension "my-extension" installed successfully
Docker Desktop に my-extension
が表示されたぁぁぁぁぁ❗️
🐳 docker extension update
コマンド
次に UI (React) と Backend (Go) それぞれのコードを修正して,Docker Extensions に更新を反映する.もう一度 docker build
コマンドを実行して,今度は docker extension update
コマンドを実行する.すると Docker Extensions に更新が反映されたぁぁぁぁぁ❗️
$ docker build -t kakakakakku/my-extension .
$ docker extension update kakakakakku/my-extension
🐳 ホットリロード
特にフロントエンド側の開発は試行錯誤を伴うため,毎回ビルドせずにコードを修正したらすぐに「ホットリロード」する仕組みがある(正確には Vite の Hot Module Replacement (HMR) を使っている).手順としては npm run dev
コマンドを実行して http://localhost:3000
に UI アプリケーションを起動し,docker extension dev ui-source
コマンドを実行して UI コンポーネントの参照先を localhost にする.あとはコードを修正するとほぼリアルタイムに Docker Desktop に反映されるため,開発体験が良くなる❗️詳しくはドキュメント参照〜
$ cd ui $ npm run dev $ docker extension dev ui-source kakakakakku/my-extension http://localhost:3000 UI source for the extension "kakakakakku/my-extension" changed to "http://localhost:3000"%
🐳 アイコンを変更する
Docker Desktop の Extensions 一覧に表示されるアイコンは初期化したプロジェクトに含まれている docker.svg
で,metadata.json
で設定する仕組みになっている.
{ "icon": "docker.svg", "vm": { "composefile": "docker-compose.yaml", "exposes": { "socket": "backend.sock" } }, "ui": { "dashboard-tab": { "title": "My-Extension", "src": "index.html", "root": "ui", "backend": { "socket": "backend.sock" } } } }
さらに docker.svg
は Dockerfile
で COPY docker.svg .
を実行してコンテナイメージに含まれている.metadata.json
と Dockerfile
を修正すると Docker Extensions のアイコンを変更できる.
ちなみに Dockerfile
に記述できる LABEL
に com.docker.desktop.extension.icon
もあって混乱するけど,LABEL は Docker Extensions を Extensions Marketplace に公開するときに使われる.二重に設定してるように感じてややこしく感じたけど,仕様である旨はドキュメントに書いてあった.
In the example Dockerfile, you can see that the image label
com.docker.desktop.extension.icon
is set to an icon URL. The Extensions Marketplace displays this icon without installing the extension. The Dockerfile also includesCOPY docker.svg .
to copy an icon file inside the image. This second icon file is used to display the extension UI in the Dashboard, once the extension is installed.
Create an advanced frontend extension | Docker Documentation
🐳 Extensions Marketplace に公開する
Docker Extensions の実装と動作確認が終わったら Extensions Marketplace に公開できる.今回は "Quickstart" を試しただけなので割愛する.公開するプロセスは以下のドキュメントに詳しく載っている.
🐳 Makefile
今回は docker extension
コマンドを実行したけど,初期化したプロジェクトには Makefile
も含まれている.よって,make build-extension
や make install-extension
など,簡単に実行することもできる❗️
$ make help Please specify a build target. The choices are: build-extension Build service image to be deployed as a desktop extension install-extension Install the extension update-extension Update the extension prepare-buildx Create buildx builder for multi-arch build, if not exists push-extension Build & Upload extension image to hub. Do not push if tag already exists: make push-extension tag=0.1 help Show this help
🐳 まとめ
今回は Docker Extensions の "Quickstart" ドキュメントを読みながら,Hello World レベルではあるけど「オレオレ Docker Extension」を実装してみた❗️実装の流れを把握できて良かった.次はもっと実用的な Docker Extension を実装してみたいぞ〜