- 图形学
- 图像处理
【免费下载链接】skia
Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.
本指南以 infra/debugger-app/README.md 为骨架,结合 infra/debugger-app/BUILD.bazel、infra/debugger-app/Makefile、bazel/skia_app_container.bzl 与 bazel/buildrc 等仓库源码,系统讲解如何用 Bazel 将 CanvasKit 构建产物注入中间 Docker 镜像、生成最终镜像、在本地运行调试以及推送到 GCR 并部署到 debugger.skia.org 的完整链路。读完你将掌握make build、docker run、make push_debugger_I_am_really_sure等核心命令的底层原理与实战用法。
一、背景:Skia Debugger 应用的镜像构建模式
Skia 官方在 debugger.skia.org 上托管了一个基于 Web 的 Skia Debugger 应用,用于在浏览器中加载并调试 Skia 的绘制命令(Skia Picture / SKP)。该应用的 Web 前端依赖 Skia 仓库产出的 CanvasKit 构建产物(WebAssembly 版本的 Skia)。
本文档描述的这个目录承载了为 debugger 应用构建最终 Docker 镜像的 Bazel 构建规则,其核心设计是:
- 一个中间镜像
debugger-app-base由 Skia 基础设施仓库(buildbot 仓库的debugger-app/BUILD.bazel)创建,内含 debugger 应用本身的 Web 服务二进制与页面资源; - 本仓库的构建规则负责把 Skia 仓库特有的CanvasKit 构建产物(Wasm 二进制、版本文件、TypeScript 类型声明)注入该中间镜像;
- 合并后的最终镜像被上传到 GCR(Google Container Registry),随后部署到 skia.org 域名下的 debugger.skia.org。
这种"应用外壳与图形库内核分离、跨仓库组装"的模式,保证了 debugger 前端可以独立演进,而图形库内核始终与当前 Skia 源码保持同步。
二、构建规则拆解:BUILD.bazel 中的 skia_app_container
最终镜像的组装逻辑全部集中在 infra/debugger-app/BUILD.bazel:
load("//bazel:skia_app_container.bzl", "skia_app_container") # Modify the debugger-app container by injecting the artifacts from this # repository on which it depends. skia_app_container( name = "debugger_container", base_image = "@debugger-app-base//image", dirs = { "/usr/local/share/debugger-app/": [ [ # This brings in all the build files. "//modules/canvaskit:canvaskit", "0644", ], [ "//modules/canvaskit:version.js", "0644", ], [ "//modules/canvaskit:npm_build/types/index.d.ts", "0644", ], ], }, entrypoint = "/usr/local/bin/debugger-app", repository = "skia-public/debugger-app-final", )各参数含义如下:
| 参数 | 值 | 说明 |
|---|---|---|
name | debugger_container | 规则名,会派生生成push_debugger_container推送目标 |
base_image | @debugger-app-base//image | 基础镜像,来自外部仓库依赖,见下文 |
dirs | 见上 | 容器内目录到文件的映射:每个条目为[Bazel 目标标签, 文件权限] |
entrypoint | /usr/local/bin/debugger-app | 容器启动入口,由 buildbot 仓库的中间镜像提供 |
repository | skia-public/debugger-app-final | 推送到 GCR 时的仓库名,最终地址为gcr.io/skia-public/debugger-app-final |
dirs中注入的三类产物分别承担不同职责:
//modules/canvaskit:canvaskit:CanvasKit 的 WebAssembly 构建产物(含全部构建文件),这是 debugger 在浏览器中实际执行 Skia 绘制的运行时核心;//modules/canvaskit:version.js:CanvasKit 版本号脚本,供前端页面展示与缓存失效控制使用;//modules/canvaskit:npm_build/types/index.d.ts:TypeScript 类型声明,供 debugger 前端以类型安全的方式调用 CanvasKit API。
它们都被放置在容器内的/usr/local/share/debugger-app/目录下,权限为0644(文件所有者可读写,其余用户只读),与镜像中其他 Web 静态资源共存。
三、底层宏:skia_app_container 的实现原理
skia_app_container是仓库复用的通用容器构建宏,定义在 bazel/skia_app_container.bzl 中(bazel/目录下还配套有 BUILD.bazel 等基础设施)。它基于rules_docker与rules_pkg,按以下步骤生成镜像:
- 逐文件生成
pkg_tar规则:对dirs字典中的每个[Bazel label, mode]元组,创建一个pkg_tar,把对应产物以指定权限放进容器内的目标目录(见宏源码 bazel/skia_app_container.bzl 中for dir in dirs循环)。这些规则带有tags = ["manual"],避免被bazel build //...之类的通配查询误触发; container_image组装镜像:以base_image为基础层,叠加所有pkg_tar,设置entrypoint与默认用户。默认用户为skia(可通过default_user参数调整,如skfe这类应用需要 root);- 可选的
container_run_and_commit:若指定了run_commands_root/run_commands_skia,宏会先在临时镜像里以对应用户执行 RUN 命令再提交为新镜像,最后用container_image恢复entrypoint与默认用户。这些目标额外带no-remotetag,因为container_run_and_commit需要本地 Docker daemon,无法在 RBE(远程构建执行)环境运行; - 生成
push_<name>推送目标:通过container_push把镜像推送到gcr.io下repository指定的仓库,tag 使用{STABLE_DOCKER_TAG}(由--workspace_status_command提供的工作区状态变量注入,见下文 buildrc 部分)。
基础镜像的来源在 WORKSPACE.bazel 中声明(约 L689-L695):
# Pulls the gcr.io/skia-public/debugger-app-base container. container_pull( name = "debugger-app-base", digest = "sha256:cf5bc2e4a408ae68ab199d65b1d7550be8ed1aaa57f97340598fc2df4e110ad6", registry = "gcr.io", repository = "skia-public/debugger-app-base", )即:构建时按digest(镜像摘要)从gcr.io/skia-public/debugger-app-base拉取不可变版本,确保可复现构建;该镜像由 Skia 基础设施仓库(buildbot)中的debugger-app/BUILD.bazel产出,其中包含 debugger 应用的 Web 服务二进制。
四、本地构建:make build 的实际执行链路
README 给出手动构建本地镜像的方式:
make build该命令在 infra/debugger-app/Makefile 中的定义如下:
BAZEL?=bazelisk .PHONY: build build: $(BAZEL) run //infra/debugger-app:debugger_container \ --config=debugger_app_container要点拆解:
BAZEL?=bazelisk表示默认使用bazelisk(Bazel 版本管理器),允许通过环境变量BAZEL覆盖为其他 Bazel 可执行文件;bazel run //infra/debugger-app:debugger_container构建并加载容器镜像到本地 Docker daemon,输出形如Loaded image ID: sha256:...与Tagging ... as bazel/infra/debugger-app:debugger_container的信息(可参考 bazel/skia_app_container.bzl 文档注释中的示例输出);--config=debugger_app_container是关键的构建配置,定义于 bazel/buildrc:
# config when building //infra/debugger-app:debugger_container. # This is invoked in a Louhi flow. build:debugger_app_container --config=ck_full_webgl2_release_debugger \ --workspace_status_command=bazel/get_workspace_status.sh它进一步展开为:
build:ck_full_webgl2_release_debugger --config=canvaskit_full --config=ck_webgl2 \ --config=release --config=ck_debugger即一次叠加四组配置,完整含义为:
| 配置 | 作用 |
|---|---|
canvaskit_full | 启用全部编解码器(gif/jpeg/png/webp 解码与 jpeg/png/webp 编码)、HarfBuzz + ICU 字体排版、自定义内嵌字体管理、CanvasKit 字体/SKP 序列化/Skottie/RuntimeEffect/Matrix 等 JS 特性,并禁用 tracing |
ck_webgl2 | 启用 WebGL 后端并禁用 legacy shader context(GPU 渲染路径) |
release | --compilation_mode=opt,优化编译 |
ck_debugger | --enable_build_for_debugger,专为 debugger 应用开启的构建开关(见 bazel/buildrc 中build:ck_debugger定义) |
同时--workspace_status_command=bazel/get_workspace_status.sh注入 git 版本等工作区状态,供{STABLE_DOCKER_TAG}使用。
五、本地运行与调试:docker run 用法
README 提供两种本地运行方式。
正常启动服务(将容器内 8000 端口映射到宿主机 8080):
docker run -p 8080:8000 -it <image ID>-p 8080:8000:宿主机 8080 端口转发到容器 8000 端口,之后在浏览器访问http://localhost:8080即可使用 debugger;-it:分配交互式 TTY,便于观察日志输出。镜像 ID 来自上一步make build输出的Loaded image ID(也可以使用 Bazel 赋予的镜像名,如bazel/infra/debugger-app:debugger_container)。
进入容器 Shell 排查问题(绕过 entrypoint):
docker run -it --entrypoint /bin/sh <image ID>--entrypoint /bin/sh会覆盖镜像中配置的/usr/local/bin/debugger-app启动入口,直接进入交互式 Shell,方便检查/usr/local/share/debugger-app/下 CanvasKit 产物是否就位、权限是否正确,或手动启动服务进程进行排障。
六、自动构建与手动推送:CI/CD 流程
README 说明:该 Docker 镜像由 Louhi(Skia 的持续集成流水线)在代码提交后自动构建并推送到 GCR,正常情况下无需人工干预。Louhi 流水线正是以--config=debugger_app_container调用与make build相同的 Bazel 目标。
仅当确有手动推送需求时,才使用以下命令(目标名中的I_am_really_sure是刻意的安全提示,提醒操作者这是面向生产 GCR 的推送动作):
make push_debugger_I_am_really_sure对应 infra/debugger-app/Makefile 中的定义:
# Review section in README.md before running this target .PHONY: push_debugger_I_am_really_sure push_debugger_I_am_really_sure: $(BAZEL) run //infra/debugger-app:push_debugger_container \ --config=debugger_app_container执行后,宏生成的container_push目标会把镜像推送到gcr.io/skia-public/debugger-app-final:<tag>。container_push同样带manual与no-remotetags——前者避免被通配构建误执行,后者是因为推送过程需要本地 Docker daemon 参与,无法在 RBE 中完成。
注意:手动推送前请仔细阅读 infra/debugger-app/README.md 的说明,并确认本地已具备访问
gcr.io/skia-public的凭据。日常迭代请优先依赖 Louhi 自动流水线。
七、延伸:同类容器构建的对照参考
debugger-app并非仓库中唯一采用skia_app_container的应用。在 bazel/buildrc 中可以看到同构的配置,例如jsfiddle_container、shaders_container、skottie_container均以ck_full_webgl2_release(或叠加 debugger 开关)为基线,配合--workspace_status_command构建各自的 Web 应用容器。若你负责维护这类应用镜像,可将本文的构建链路(Makefile → Bazel config → skia_app_container 宏 → container_pull 基础镜像)作为通用参考模板,只需替换dirs中注入的产物与repository名称。
八、常见问题排查速查
make build报错提示找不到@debugger-app-base//image:确认网络可访问gcr.io且已执行bazel fetch拉取外部依赖;该镜像按 digest 锁定(见 WORKSPACE.bazel),内容变更需由 buildbot 仓库重新发布。bazel run卡在 RBE 相关报错:container_run_and_commit与container_push目标带有no-remotetag,需在本地执行、确保 Docker daemon 运行中。- 镜像内 CanvasKit 产物缺失:通过
docker run -it --entrypoint /bin/sh <image ID>进入容器,检查/usr/local/share/debugger-app/目录下是否存在 canvaskit 构建文件、version.js与index.d.ts,并核对文件权限是否为0644。 - 端口映射不生效:确认容器实际监听端口是 8000(
-p 8080:8000中的后半段),这与 debugger 应用服务默认端口保持一致。
以上全部命令与配置均以当前仓库实际内容为准,可直接在本地复现make build→docker run的完整本地验证流程,而生产环境的自动构建与推送则交给 Louhi 流水线完成。
- 图形学
- 图像处理
【免费下载链接】skia
Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.
相关推荐
Skia Debugger 应用 Docker 镜像构建指南:从 CanvasKit 到 debugger.skia.org 的交付链路
Skia Debugger 应用 Docker 镜像构建指南:从 CanvasKit 到 debugger.skia.org 的交付链路 本指南围绕 Skia
图形学Skia 的 GCC Docker 构建镜像:infra/gcc 镜像体系与 Bazel/GN 构建实践
Skia 的 GCC Docker 构建镜像:infra/gcc 镜像体系与 Bazel/GN 构建实践 导读 Skia 的日常构建默认以 Clang 为主,但
图形学Skia jsfiddle Docker 镜像构建指南:从 CanvasKit Bazel 制品到 jsfiddle.skia.org 部署
Skia jsfiddle Docker 镜像构建指南:从 CanvasKit Bazel 制品到 jsfiddle.skia.org 部署 导读 本文基于 i
图形学
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考