wouterdebie/davit

GitHub: wouterdebie/davit

Davit 是 Apple Container 平台的原生 macOS 图形管理工具,为 Apple silicon 上的轻量级 Linux 容器提供完整的可视化生命周期管理能力。

Stars: 763 | Forks: 10

# Davit **Apple [container](https://github.com/apple/container) 平台的原生 macOS UI** — 类似于 OrbStack/Docker Desktop,但专门用于 Apple silicon 设备中 Apple 提供的“将 Linux 容器作为轻量级虚拟机”技术栈。 完全使用 SwiftUI 构建(没有 Electron,也没有 web 视图)。Davit 链接了 Apple 自带的 **`ContainerAPIClient`** 库,并**通过 XPC 直接**与 `container-apiserver` 通信 — 这与 `container` CLI 使用的通信路径完全相同。程序中从不调用 CLI 二进制文件:列表、 生命周期管理、实时状态、日志流、镜像拉取、卷/网络管理、终端内 shell (`davit exec`), 甚至 launchd 服务引导,全部通过 API 完成。 ## 功能 - **仪表盘** — 服务状态支持一键启停,资源统计,磁盘使用情况(带可回收空间清理菜单),以及跨运行中容器的实时聚合 CPU 图表。 - **容器** — 列表显示每个容器的实时 CPU/内存/IP,支持启动/停止/强制停止/重启/删除、清理、搜索,以及**编辑与重建**(由于容器在此平台上是不可变的,因此“编辑”会打开一个预填了该容器端口/环境变量/挂载点/资源/网络配置的运行面板 — 并会减去镜像本身的 entrypoint/CMD/环境变量,只显示*您的*自定义配置 — 确认后即替换原容器)。详情视图包括: - *概览*:镜像、命令、平台、资源、网络(IP/MAC/网关/主机名)、已发布端口(支持“在浏览器中打开”)、挂载点、环境变量、标签。 - *日志*:流式 `-f` 跟踪模式、启动日志开关、tail 选择器、复制。 - *统计*:实时 CPU 百分比、内存和磁盘 I/O 图表 (Swift Charts);CPU、内存、已用磁盘空间、网络和进程数的磁贴。 - *检查*:格式化高亮的原始 JSON。 - *终端*:在 Terminal/iTerm 中打开交互式 shell(通过 XPC 执行 `davit exec`)。 - *文件*:浏览容器文件系统 — 导航、下载、上传、删除(通过 `exec` 及复制进出)。 - **镜像** — 支持显示流式进度的拉取、**拉取最新版本**以将任意镜像的标签刷新为最新摘要(通过右键菜单或镜像详情)、从镜像运行、打标签、删除、清理;支持查看单个镜像的平台变体、大小、摘要及“正在使用此镜像的”容器。 - **卷** — 创建(指定大小)、删除、清理、在 Finder 中显示底层镜像、使用中状态标记。 - **网络** — 创建(子网 / 内部网络)、删除、清理、查看已连接容器数量。 - **机器** — Apple 的容器机器(轻量级通用虚拟机,挂载您的主目录并具有稳定的 `.machine` DNS 名称):从任意镜像创建并配置 CPU/内存大小、启动/停止、设为默认、删除;详情视图支持查看配置概览、流式日志、实时统计和检查 JSON;一键开启**终端**进入机器的登录 shell;编辑 CPU/内存/主目录挂载(在下次启动时生效)。支持无界面模式:`Davit machine list|create|boot|stop|delete|exec|set`。 - **运行容器面板** — 镜像选择器、名称、命令、端口、环境变量、卷/绑定挂载、CPU/内存限制、网络选择。 - **构建镜像** — 镜像 → 构建镜像:选择上下文文件夹和 Dockerfile,设置 tag/build-args,Davit 会驱动平台的 BuildKit 构建器(如有需要则先启动它),然后将结果加载并打标签存入镜像库。支持无界面模式:`Davit build -t `。 - **Compose 导入** — 容器 → ⋯ → 导入 Compose 文件:解析 compose 文件,精确预览将要创建的内容(按 `depends_on` 顺序排列的服务、命名的卷、网络、每个服务对应的 `container run` 命令,以及对不支持功能的警告),然后创建并启动整个技术栈 — 支持 `healthcheck`、`profiles`、`depends_on` 条件(`service_healthy`、`service_completed_successfully`)、`env_file:`/`entrypoint:`,以及从文件同级 `.env` 中合并并在进程环境变量下的 `${VAR}` 插值。无界面模式:支持完整生命周期 — `Davit compose plan | up [-d] | down [-v] | ps | logs [-f\|--follow] [--tail ] | stop | start | restart | pull | exec `,每个命令均支持 `[-f ] [--env-file ] [--profile

]… [service…]` — 像 docker 一样自动发现文件(`compose.yaml`、`compose.yml`、`docker-compose.yml`、`docker-compose.yaml`,并遍历父目录;`COMPOSE_FILE` 优先)。命名服务会限制命令范围:`plan`/`up` 会添加依赖闭包,而 `stop`/`start`/`restart`/`pull`/`ps` 和 `down` 仅应用于指定的服务(docker 的行为)。服务发现:由于平台的 DNS 无法解析 compose 服务名,因此 `up`/`start`/`restart` 会向项目中的每个正在运行的容器写入受管理的 `/etc/hosts` 条目(后缀为 `# davit-compose`),将每个服务和容器名映射到其当前 IP — 每次运行时都会刷新,因此重建后的服务新 IP 能够被一直保持运行的容器访问到。注意事项:在 compose 外部重建的容器会保留过时条目,直到下一次执行 `up` 或 `start`;没有 `/bin/sh` 的镜像无法被修补(会有警告)。 - **镜像仓库** — 登录 Docker Hub / ghcr.io / 任何镜像仓库以拉取私有镜像(设置 → 镜像仓库);凭据会针对镜像仓库进行验证,并存储在登录钥匙串中,与 `container` CLI 共享。同时也支持 **Docker 凭据助手**:如果 `~/.docker/config.json` 包含针对某个镜像仓库的 `credHelpers`/`credsStore` 条目(例如通过 `gcloud` 的 Google Artifact Registry、ECR 等),Davit 会在每次拉取前调用该助手,并为平台暂存短生命周期的 token,因此每小时过期的凭据也能始终正常工作。 - **菜单栏扩展** — 服务状态,随处可用的针对单个容器的快捷操作。 - **自动启动容器** — 将任何容器标记为“Davit 启动时同步启动”(右键菜单);启动时,Davit 会根据需要拉起平台服务并启动它们。配合*登录时打开*,当您坐在电脑前时,容器已经在运行了。 - **登录时打开** — 可选的登录时启动至菜单栏功能(设置 → 通用),通过 `SMAppService` 实现。 - **应用内更新** — 每天检查 GitHub Releases(或从“关于”界面按需检查);一键下载新版本,验证其 Developer ID 签名(开发团队必须匹配),以原子方式替换并支持回滚的 bundle,然后重启应用。支持无界面模式:`Davit update check|install`。 - **设置** — 平台安装根目录覆盖及刷新频率(通用),外加完整的**平台配置编辑器**(平台标签页):默认容器 CPU/内存、镜像仓库、本地 DNS 域名、构建器资源/Rosetta,以及高级参数(内核、init 镜像、机器)。只有与安装默认值不同的值才会被写入 `~/.config/container/config.toml`,会保留 `[plugin.*]` 部分,每次保存都会在提交前通过平台自带的配置加载器进行验证,并且结果会立即发布到应用根目录 — 容器默认值/镜像仓库/DNS 会立即应用于新操作,而 daemon 端的设置则在服务重启后生效(提供有重启按钮)。 ## 环境要求 - Apple silicon Mac,macOS 15+(推荐 macOS 26 — 以匹配 `container` 1.1) - 已安装 [apple/container](https://github.com/apple/container/releases)(或内置打包,见下文) ## 发布 标记 `v*` 会触发 GitHub Actions 工作流,在 macOS runner 上构建应用,并将 `Davit-.zip` (+ sha256) 附加到 GitHub Release 中。 设置了这些仓库密钥后,发布的版本将带有 Developer ID 签名(hardened runtime)并经过公证,因此它们可以像任何其他应用一样直接打开: | Secret | Value | |---|---| | `MACOS_CERT_P12` | 导出的 "Developer ID Application" 证书的 base64 编码 (`base64 -i cert.p12`) | | `MACOS_CERT_PASSWORD` | .p12 导出密码 | | `APPLE_ID` | 您的 Apple ID 邮箱 | | `APPLE_TEAM_ID` | 10 字符的团队 ID (developer.apple.com → Membership) | | `APPLE_APP_SPECIFIC_PASSWORD` | 从 appleid.apple.com 获取的 App 专用密码 | 如果没有这些密钥,构建版本将回退为临时签名 (ad-hoc),并且发布说明中会包含 `xattr -dr com.apple.quarantine` 的变通方法。 ## 安装 ``` brew install wouterdebie/tap/davit ``` (Homebrew 6 在首次使用时会要求您信任第三方 tap:`brew trust wouterdebie/tap`。) 或者从 [Releases](https://github.com/wouterdebie/davit/releases/latest) / [davit.app](https://davit.app) 下载已签名的 zip 包。 ## 快速上手 从全新安装到在浏览器中运行某些内容: 1. **打开 Davit。** 首次启动时,如果未安装 Apple 的 container 平台,Davit 会为您下载并安装它 — 无需管理员密码。 2. **拉取演示镜像** — 镜像 → 拉取镜像 → `nginxdemos/hello`(体积小,并且它会提供一个可见的页面)。 3. **映射端口并运行** — 运行该镜像,将宿主机 `8088` 端口映射到容器 `80` 端口。 4. **打开它** — 容器的“端口”行有*在浏览器中打开*选项,或者直接访问 `localhost:8088`。您会看到一个由容器内部服务提供的页面,显示其自身的主机名和 IP。 5. **探索** — 实时 CPU/内存/磁盘、流式日志、一键终端,以及用于更改端口/环境变量/资源的编辑与重建功能。 ## 构建与运行 ``` scripts/bundle.sh # builds release binary + assembles dist/Davit.app open dist/Davit.app ``` 原生的 `swift build` / `swift run` 也可用于开发环境(没有 bundle,因此没有图标和菜单栏等额外功能)。 ## 仍然必须安装的内容 API 移除了对 CLI 的依赖,但**并未**移除对平台的依赖:`container-apiserver` 及其运行时/网络插件二进制文件属于宿主机 launchd 服务,库仅与它们进行 通信。Davit 按以下顺序解析平台安装根目录: 1. “设置”中的自定义安装根目录 2. Davit 托管的安装位置,位于 `~/Library/Application Support/dev.wouter.davit/platform/` 3. `/usr/local`(官方安装程序的路径) 4. 内置于应用程序内部的 `Davit.app/Contents/Resources/vendor` **应用内安装:** 当未找到平台时,引导界面会提供一键 安装 — Davit 下载 Apple 签名的安装 pkg 包(带有实时进度条), 验证代码签名,将 payload 解压到受管理的根目录(与官方 安装程序不同,无需管理员权限),并从该处引导启动 各项服务。设置 → 通用还可以安装 `container` shell 命令:在 `/usr/local/bin` 中放置一个 wrapper,在执行真正的 CLI 之前将 `CONTAINER_INSTALL_ROOT` 固定到 受管理的根目录(仅需一次管理员授权提示;简单的符号链接将是 错误的,因为 CLI 是从其未解析的可执行路径推导安装根目录的)。受管理的副本在解析顺序中 排在 `/usr/local` 之前是刻意为之的:它始终与应用链接的客户端 版本相匹配,因此较新的系统 daemon 不会破坏 XPC 兼容性。 同样支持无界面模式:`Davit platform install|remove`。 要发布一个无需系统安装程序即可运行的完全自包含的应用: ``` scripts/vendor.sh 1.0.0 # downloads the official signed .pkg, extracts payload into Vendor/container scripts/bundle.sh --vendor # bundles it into the app ``` 服务启动/停止是在进程内实现的(使用来自 `ContainerPlugin` 的 LaunchPlist + ServiceManager — 即运行 `container system start` 的相同代码),并指向 解析出的任意安装根目录。内核和 init 镜像安装会在 首次启动时以非交互方式处理。应用程序数据位于标准的 `~/Library/Application Support/com.apple.container/` 中,因此 Davit 和 CLI(如果 已安装)看到的是完全相同的容器。 **版本固定:** SPM 对 apple/container 的依赖被精确固定 `exact: "1.0.0"` 以 匹配 daemon;客户端和 apiserver 同步发布,且 XPC 协议并非 稳定的公共 API。当已安装的平台更新时,请提升固定版本并重新构建。 作为记录,内置打包的权衡包括:bundle 体积会增加约 150 MB,您需要自行掌控 工具链的更新节奏,并且 launchd 服务是从 应用 bundle 内部注册的(因此移动/删除应用会使它们变为孤立状态,直到执行 `container system stop` 为止)。 默认设置仍然是“使用系统安装”,因为官方 pkg 会将服务保留在 `/usr/local` 下并独立进行更新。 ## 二进制模式 该应用程序二进制文件同时也充当一个小工具: ``` Davit exec [command…] # interactive TTY shell — or a one-off command — in a container (used by "Open Terminal") Davit selftest # end-to-end test of the XPC service layer against the live daemon Davit system start|stop # bootstrap / tear down the container launchd services Davit platform install|remove # download + verify Apple's signed pkg into an app-managed install root Davit registry login|list|logout # registry credentials (login reads the password from stdin) Davit compose [-f ] [--env-file ] [--profile

]… [service…] # subcommands: plan | up [-d|--detach] | down [-v|--volumes] | ps | logs [-f|--follow] [--tail ] # stop | start | restart | pull | exec # file autodiscovered like docker; .env + ${VAR} interpolation; naming services scopes the # command (plan/up add the dependency closure; stop/start/restart/pull/ps/down take exactly # the named services). In-container service names resolve via managed /etc/hosts entries, # re-synced on every up/start/restart — recreates outside compose need another up/start. Davit build -t

# build an image from /Dockerfile via the BuildKit shim Davit machine list|create|boot|stop|delete # container machines (micro VMs) Davit --snapshot /tmp/shots # render every screen to PNGs via ImageRenderer (no screen-recording permission) ``` ## 架构 ``` Sources/ContainerStack/ Main.swift entry point + exec/selftest/system binary modes Backend.swift XPC service layer on ContainerAPIClient: ContainerService facade, SystemController (launchd bootstrap), LogStreamer (FileHandle tail/follow), PullProgressModel, TerminalLauncher, platform install resolution Models.swift view models mapped from ContainerResource types (views stay decoupled from the unstable library API) AppState.swift @MainActor store: polling (4s data / 2s stats), CPU% derivation, actions SnapshotDriver.swift --snapshot harness App.swift SwiftUI scenes, menu bar extra Views/ Shell (sidebar), Dashboard, Containers, ContainerDetail, Images, VolumesNetworks, Sheets (run/pull/create), Settings, Components ``` 统计信息说明:daemon 报告的是累计的 `cpuUsageUsec`;Davit 根据轮询之间的增量计算得出 CPU% ,并按实际时间进行标准化(100% = 占满一个完整的核心)。
标签:Docker桌面, macOS原生应用, SwiftUI, 容器管理, 开发运维工具, 苹果容器平台