深入理解 containers/storage:Go 语言实现的 Layer、Image、Container 容器存储层管理库
云原生后端前端运维可观测性开发工具【免费下载链接】octantHighly extensible platform for developers to better understand the complexity of Kubernetes clusters.项目地址https://gitcode.com/gh_mirrors/oc/octant点击查看免费下载containers/storage是一个以 Go 语言编写、面向容器运行时场景的存储库核心目标是统一管理文件系统层Layer、容器镜像Image与容器Container三类对象的持久化数据。本文以其官方 README仓库内位于 vendor/github.com/containers/storage/README.md为骨架结合同目录下的源码、配置与构建文件完整讲解其对象模型、标识机制、元数据/大数据存储方式、CLI 构建流程与storage.conf配置体系帮助读者理解容器存储的底层抽象并能在实际项目中正确初始化与使用该库。在 Octant 项目中该库以间接依赖形式引入go.mod 声明github.com/containers/storage v1.37.0 // indirect版本信息见 VERSION其完整源码被 vendor 到vendor/github.com/containers/storage/下可作为离线阅读与研究的参照实现。一、库的定位为层、镜像与容器提供统一存储抽象README 开篇即明确了该库的使命提供存储文件系统层、容器镜像和容器的方法并附带一个名为containers-storage的 CLI 包装程序供手工操作和脚本化使用。从源码结构看这一目标通过三层抽象落实存储驱动层drivers/目录下实现了overlay、aufs、btrfs、vfs、devmapper、zfs、windows等多种 graph driver由drivers/register/中的各register_*.go文件按构建标签如 register_overlay.go 中的build !exclude_graphdriver_overlay,linux,cgo选择性注册通用工具层pkg/下提供archivetar 归档与 diff、lockfile文件锁、idtoolsUID/GID 映射、mount、unshare、quota等与存储强相关的底层能力Store 门面层store.go中的Store接口与GetStore工厂函数把上述能力整合为对调用方友好的单一入口。二、核心对象模型Layer、Image、Container 三者的关系README 用三段话精确刻画了三种被管理对象Layer写时复制COW的文件系统层Alayeris a copy-on-write filesystem which is notionally stored as a set of changes relative to itsparentlayer, if it has one.Layer 是一个写时复制copy-on-write文件系统逻辑上存储为相对于其父层parent layer的一组变更。约束与特性一个 layer只能有一个父层任何 layer 都可以成为多个 layer 的父层多子一父的树状结构作为其他 layer 父层的 layer 应视为只读避免并发写导致数据破坏。源码中的Layer结构体layers.go与之一一对应ID、Names、Parent字段记录了层自身标识与父层 IDMetadata字段用于存放调用方自定义的小型数据。Image指向顶层 Layer 的引用 附加信息Animageis a reference to a particular layer (itstoplayer), along with other information which the library can manage for the convenience of its caller.Image 是对某个特定 layer称为其 top layer的引用同时携带库为调用方代管的附加信息典型内容包括运行镜像内二进制所需的配置模板如启动参数、环境变量可能包含的加密签名cryptographic signatures用于校验镜像来源与完整性。关键特性多个 Image 可以引用同一个 Layer——两个镜像的差异可能并不体现在 layer 内容上而只体现在附加信息上。例如同一层数据可以分别被打上“生产签名”与“测试签名”形成两个镜像。Image结构体images.go中除ID、Names外还定义了Digest与Digests字段用于按摘要digest定位镜像呼应了签名/校验相关的表述。Container镜像顶层 Layer 之上的读写层Acontaineris a read-write layer which is a child of an images top layer, along with information which the library can manage for the convenience of its caller.Container 是一个读写read-writelayer它是镜像顶层 layer 的子层同时携带该容器特有的运行配置信息。典型关系多个 Container 可以从同一个 Image 派生——每个容器共享镜像的只读层只在自己的读写层上记录差异这正是容器“镜像启动、实例独立”的存储基础。Container结构体containers.go通过ImageID字段记录其来源镜像通过Metadata保存该容器特有的配置数据。三层对象关系小结Layer只读COW 变更集可有多个子层 └── Image引用顶层 Layer 配置模板/签名多 Image 可共享同一 Layer └── ContainerImage 顶层 Layer 的子读写层 运行配置多 Container 派生自同一 Image三、标识体系32 位十六进制 ID 与名称自动解析README 说明Layer、Image、Container 三类对象主要以 32 字符十六进制 ID 表示同时每类对象都可以附加一个或多个任意名称names当 API 调用期望 ID 而调用方传入名称时库会自动将名称解析为 ID。源码层面Store接口与store实现提供了对应的名称解析能力Names(id string) ([]string, error)读取某对象已附加的全部名称store.goLookup(name string) (string, error)把名称反向解析为 IDstore.go名称在同类对象内保持唯一Layer.Names、Image.Names、Container.Names字段注释均声明 Names are unique among ...。此外CreateLayer/CreateImage等创建方法均支持“ID 为空时由库自动生成”例如 store.go 中CreateImage在id 时调用stringid.GenerateRandomID()生成随机 ID。ID 的生成逻辑位于 pkg/stringid/stringid.go。四、两类附属数据Metadata 与 Big DataREADME 区分了两种不同量级的附属数据理解这一区分对正确使用 API 至关重要。Metadata小型、常驻内存的元数据This is expected to be a small piece of data, since it is cached in memory and stored along with the librarys own bookkeeping information.Metadata预期是小体量数据原因有二它会被缓存在内存中并且与库自身的簿记信息bookkeeping information一同落盘存储。因此它适合存放诸如镜像描述、容器运行参数等轻量信息不宜存放大块内容。对应接口见 store.goROMetadataStore.Metadata(id)读取、RWMetadataStore.SetMetadata(id, metadata)写入。Big Data按名存储的大数据块This is a named chunk of larger data, which is only in memory when it is being read from or being written to its own disk file.Big Data是有名称的大数据块仅当正在读写其独立磁盘文件时才驻留内存平时不占内存。它面向 Image 与 Container以及 Layer的较大附属数据例如镜像清单、签名数据等。对应接口同样定义在 store.goROBigDataStore提供BigData、BigDataSize、BigDataDigest、BigDataNamesRWImageBigDataStore.SetBigData与RWLayerBigDataStore.SetBigData负责写入。BigDataDigest返回github.com/opencontainers/go-digest的摘要值说明大数据块也纳入摘要校验体系。五、构建与运行make binary与 Vagrant 虚拟机README 给出了两条与构建直接相关的操作指引构建 CLI 包装器make binaryTo build the CLI wrapper, use make binary.Makefile 中确认了这一目标containers-storage: $(sources) ## build using gc on the host $(GO) build $(MOD_VENDOR) -compiler gc $(BUILDFLAGS) ./cmd/containers-storage binary local-binary: containers-storage即make binary等价于make local-binary最终通过go build编译出名为containers-storage的可执行文件供手工与脚本化使用。跨平台与虚拟机构建README 补充说明使用 VM 的构建操作默认通过vagrant启动虚拟机默认使用其libvirt provider官方准备的 box 同样支持virtualbox provider可通过在启动构建前设置环境变量$VAGRANT_PROVIDERvirtualbox来切换。仓库根部的 Vagrantfile 即对应这一机制Makefile 中的test、test-unit、test-integration、validate等目标均通过$(RUNINVM) make local-...在 VM 内执行见 Makefile。需要说明VM 构建机制面向该库的上游开发流程在 Octant 项目中仅作为 vendored 依赖存在实际使用直接依赖 Go 库 API 即可。六、配置文件storage.conf驱动、路径与选项README 虽未逐项列出配置项但仓库自带一份完整可用的示例配置 storage.conf它是所有使用该库工具的统一配置文件配置解析结构见 types/options.go 的tomlConfig。以下为关键段落[storage]主表驱动与存储路径[storage] # 默认存储驱动必须设置以保证正常运行 driver overlay # 临时存储位置存放活动挂载点等重启即失的运行期信息 runroot /run/containers/storage # 容器存储的主要读写位置存放 layer、image、container 内容 graphroot /var/lib/containers/storage # rootless非 root用户的存储路径 # rootless_storage_path $HOME/.local/share/containers/storagedriver存储驱动名。示例为overlay可选值还包括vfs、btrfs、aufs、devicemapper、zfs等取决于编译时注册的驱动runroot存放运行期信息如活动挂载点位置的目录主机重启后应允许丢失graphroot存放layer/image/container 实际内容的持久化目录rootless_storage_pathrootless 用户专属存储路径。源码层面StoreOptions结构体types/options.go中的RunRoot、GraphRoot、RootlessStoragePath、GraphDriverName、GraphDriverOptions、UIDMap/GIDMap等字段与配置逐项对应其中注释明确指出GraphDriverName仅在首次为某个 RunRootGraphRoot 初始化 Store 时需要指定。[storage.options]镜像源、UID/GID 映射与用户命名空间[storage.options] # 附加只读镜像源逗号分隔 additionalimagestores [] # 容器内 UID/GID 与容器外 UID/GID 的映射子集映射受内核限制 # remap-uids 0:1668442479:65536 # remap-gids 0:1668442479:65536 # 通过 /etc/subuid、/etc/subgid 中的用户名自动查找映射范围 # remap-user containers # remap-group containers # root 用户自动创建用户命名空间时使用的用户名 # root-auto-userns-user storage # 自动创建的用户命名空间最小/最大尺寸 # auto-userns-min-size1024 # auto-userns-max-size65536additionalimagestores附加的只读镜像存储路径列表。解析时会被拼装为driver.imagestorepath传给驱动见 types/options.goremap-uids/remap-gids显式 ID 映射格式为容器内起始ID:宿主机起始ID:长度README 所述“内核允许的映射数量有限”在注释中被再次强调remap-user/remap-group按用户名从/etc/subuid、/etc/subgid读取映射区间root-auto-userns-user、auto-userns-min-size、auto-userns-max-size面向自动创建用户命名空间的配置rootless 场景下忽略。[storage.options.overlay]overlay 驱动专属选项[storage.options.overlay] # 允许非特权用户在用户命名空间内以单一 UID 运行容器 #ignore_chown_errors false # 镜像最大 inode 数 # inodes # 使用辅助程序如 fuse-overlayfs完成挂载 #mount_program /usr/bin/fuse-overlayfs # 逗号分隔的额外挂载选项 mountopt nodev # 跳过对存储主目录的 PRIVATE bind mount # skip_mount_home false # 镜像最大尺寸 # size # 新文件/目录的强制权限掩码shared(0755)/private(0700)/八进制数 # force_mask 其中force_mask值得注意其注释明确指出这是实验性功能且设置后原始权限掩码会被存入user.containers.override_statxattr同时必须指定mount_program——挂载程序如/usr/bin/fuse-overlayfs会把扩展属性权限呈现给容器内进程而非直接应用force_mask权限。源码在 storage.conf 中对shared与private两种取值给出了详尽的行为说明包括“private等价 0700”“shared会使镜像内所有文件对系统所有用户可读可执行”等安全提示。[storage.options.thinpool]devicemapper 精简池选项[storage.options.thinpool] # 池触发扩容时增长的百分比相对池大小 # autoextend_percent 20 # 触发扩容的池使用率阈值百分比 # autoextend_threshold 80 # 基础设备尺寸限制镜像与容器大小 # basesize 10G # 自定义块大小 # blocksize64k # 精简池使用的自定义块设备配置 devicemapper 时必须 # directlvm_device # 即使设备已有文件系统也强制擦除 # directlvm_device_force True # 基础设备文件系统类型 # fsxfs # devicemapper 日志级别0 抑制7 Debug # log_level 7 # 新建设备所需的最小空闲空间百分比0%-99%0 表示禁用 # min_free_space 10% # 创建基础设备时的额外 mkfs 参数 # mkfsarg # pvcreate --metadatasize 参数默认 128k # metadata_size # 标记设备延迟移除/延迟删除 # use_deferred_removal True # use_deferred_deletion True # XFS 在 ENOSPC 时重试 IO 的最大次数 # xfs_nospace_max_retries 0该段适用于以 device mapper 精简池为后端的场景多数项为可选directlvm_device是部署 devicemapper 驱动时的必填项。七、底层初始化GetStore与StoreOptions的加载链理解配置如何生效需要追踪GetStore的初始化链路这也是 README 所述“库管理三类对象”能力的落地入口。StoreOptions 的默认值与配置文件加载types/options.go 的init()设置了与storage.conf完全一致的默认值defaultStoreOptions.RunRoot /run/containers/storage defaultStoreOptions.GraphRoot /var/lib/containers/storage defaultStoreOptions.GraphDriverName ReloadConfigurationFileIfNeeded(defaultConfigFile, defaultStoreOptions)系统级配置文件默认为/etc/containers/storage.conf见 types/options.go。ReloadConfigurationFiletypes/options.go负责用 TOML 解析[storage]表中的driver、runroot、graphroot、rootless_storage_path将additionalimagestores、size、mount_program、mountopt、force_mask、ignore_chown_errors等拼装为driver.optionvalue形式的GraphDriverOptions处理remap-user/remap-group自动补齐另一侧与remap-uids/remap-gids通过idtools生成UIDMap/GIDMap应用环境变量STORAGE_DRIVER强制覆盖驱动名与STORAGE_OPTS覆盖驱动选项逗号分隔。rootless 场景下getRootlessStorageOptstypes/options.go会默认将GraphRoot设为$HOME/.local/share/containers/storage、RunRoot设为 rootless 运行目录驱动优先选择overlay若内核不支持原生 overlay 且系统存在fuse-overlayfs则自动追加overlay.mount_program路径否则回退到vfs。GetStore单例复用与目录初始化store.go 的GetStore(options types.StoreOptions)是库的唯一入口其关键行为空参数回退若调用方未传任何选项则使用types.Options()返回的默认选项路径规范化将GraphRoot、RunRoot转为绝对路径单例缓存通过全局stores切片与storesLock互斥锁对相同graphRoot 驱动名的组合复用已初始化的 Store目录与锁初始化os.MkdirAll创建runroot、graphroot及其下mounts、tmp、driver子目录并在 graphroot 下创建storage.lock、userns.lock文件锁。之后调用方即可通过Store接口store.go执行CreateLayer、CreateImage、CreateContainer、Mount/Unmount、Metadata/SetMetadata、BigData/SetBigData、Delete等完整操作——这些正是 README 所述对象管理能力的 API 形态。八、在 Octant 项目中的定位与阅读建议作为 Octant面向 Kubernetes 集群的可扩展开发者平台的间接依赖containers/storage v1.37.0以 vendor 形式固定在 vendor/github.com/containers/storage/其存在意义是为依赖链中的镜像/容器存储操作提供底层能力。对想要深入容器存储原理的读者建议按以下顺序研读README本文主题建立对象模型认知layers.go、images.go、containers.go 对照结构体字段理解三类对象的完整属性store.go 追踪GetStore初始化与Store接口方法族storage.conf 与 types/options.go 对照配置与解析逻辑需要时再深入 drivers/ 各驱动的挂载与差异计算实现。总结containers/storage用一套简洁的对象模型解决了容器存储的核心问题以Layer只读、多子一父的 COW 变更集承载镜像内容以Image顶层 Layer 引用 配置模板/签名描述镜像以ContainerImage 顶层 Layer 上的读写子层 运行配置实例化容器配合 32 字符十六进制 ID 名称自动解析的标识体系、metadata内存缓存与big data按需落盘两种附属数据以及storage.conf驱动的多后端存储驱动构成了一个可被containers-storageCLI 与任意 Go 程序直接调用的完整存储框架。理解这套抽象也就理解了绝大多数现代容器运行时在“镜像分层、实例共享、存储驱动可插拔”方面的设计共性。赞分享云原生后端前端运维可观测性开发工具【免费下载链接】octantHighly extensible platform for developers to better understand the complexity of Kubernetes clusters.项目地址https://gitcode.com/gh_mirrors/oc/octant点击查看免费下载相关推荐skopeo 仓库内嵌的 storage 库解析Go 语言容器分层存储Layer/Image/Container完整指南skopeo 仓库内嵌的 storage 库解析Go 语言容器分层存储Layer/Image/Container完整指南 导读 本文以 skopeo 仓库云原生CLI镜像仓库Docker存储驱动终极指南深入解析Layer分层与GraphDriver实现原理 Docker存储驱动终极指南深入解析Layer分层与GraphDriver实现原理 想要真正掌握Docker的核心技术理解Docker存储驱动和Lay云原生容器运行时虚拟化容器编排深入解析 go.podman.io/storage容器层、镜像与容器的存储模型及 containers-storage 工具深入解析 go.podman.io/storage容器层、镜像与容器的存储模型及 containers storage 工具 go.podman.io/sto云原生上一篇StarRocks Query Detail API 完全指南通过 FE HTTP 接口获取查询执行明细下一篇在 Next.js 中集成 CKEditor 5CDN 方式App Router 与 Pages Router 完整实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

云端 Web UI 访问异常:先查端口链路,还是先查应用配置?

云端 Web UI 访问异常:先查端口链路,还是先查应用配置?

云端 Web UI 访问异常:先查端口链路,还是先查应用配置? 云端运行 Web UI、Dashboard、推理服务或开发工具时,经常会出现两类看起来很像的问题: 一种是服务进程已经启动,但浏览器完全访问不到。 另一种是主页…

2026/10/10 2:39:02 阅读更多 →
27. 数据产品-数据管理知识体系

27. 数据产品-数据管理知识体系

DAMA-DMBOK2.0(DAMA 数据管理知识体系指南 第 2 版)DMBOK2 是 DAMA International 发布的数据管理权威框架,也是 CDGA / CDGP 认证的指定教材;核心形象为DAMA 车轮图:轮毂 数据治理(总控)&…

2026/10/10 2:39:02 阅读更多 →
AI大模型如何抓取和推荐徐州本地商户?GEO技术链路与POI权重算法拆解

AI大模型如何抓取和推荐徐州本地商户?GEO技术链路与POI权重算法拆解

一、技术背景:AI大模型正在重构本地服务流量分发 2026年初,DeepSeek R1等新一代推理模型的发布标志着AI大模型技术进入成熟应用阶段。用户行为数据显示,本地服务信息的获取方式正在从"搜索引擎检索"转向"AI对话问答"——…

2026/10/10 2:39:02 阅读更多 →

最新新闻

Docker安装报错全解析:从daemon权限到内核模块的排查指南

Docker安装报错全解析:从daemon权限到内核模块的排查指南

你有没有遇到过这样的场景:费了好大劲把 Docker 装上,兴冲冲地敲下docker ps,结果屏幕上一行红字:permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock这种感觉就像门锁装好了…

2026/10/10 3:19:15 阅读更多 →
CE318太阳光度计数据处理:AOD与WV反演实战指南

CE318太阳光度计数据处理:AOD与WV反演实战指南

简介:这份资源面向大气科学、遥感与气象观测方向的学习者和科研人员,围绕CE318型太阳光度计的观测数据,提供从原始数据读取到气溶胶光学厚度(AOD)与水汽含量(WV)反演的完整处理思路。资源包共5个…

2026/10/10 3:19:15 阅读更多 →
C++排序选型指南:sort、stable_sort与partial_sort

C++排序选型指南:sort、stable_sort与partial_sort

最开始被排序这件事坑到,是在某个线上榜单的开发任务里。数据量其实不大,也就几千条,需求说得很直白:按分数从高到低排,分数相同的先提交者靠前。我想都没想就调了sort,自己写了个分数比较的lambda&#xf…

2026/10/10 3:19:15 阅读更多 →
环境模拟中的木马程序分析:从渗透测试到防御反推

环境模拟中的木马程序分析:从渗透测试到防御反推

"基于环境模拟的木马程序制作与渗透测试"——说实话,第一次看到这个标题的人,多半会以为这是某种"黑客速成教程"。但我做了几年安全方向的研究,可以负责任地说:真正有价值的东西不在"制作"本身&…

2026/10/10 3:19:15 阅读更多 →
练得够不够狠?openGym的RIR/RPE努力度评分及统计功能详解

练得够不够狠?openGym的RIR/RPE努力度评分及统计功能详解

练得够不够狠?openGym的RIR/RPE努力度评分及统计功能详解 【免费下载链接】openGym https://github.com/DuarteSantos8/openGym 项目地址: https://gitcode.com/gh_mirrors/ope/openGym openGym 是一款自托管的健身训练追踪器,除了记录重量和次数…

2026/10/10 3:19:15 阅读更多 →
C++编译期分支全解析:if constexpr、enable_if与标签分发

C++编译期分支全解析:if constexpr、enable_if与标签分发

1. 为什么编译期的“分支”值得单独拿出来讲1.1 一个每天都在发生的真实场景写 C 模板写久了,谁都会被同一件事卡过:函数模板里拿到一个泛型 T,你想对不同的 T 做不同的处理,最直觉的写法是在函数体里写一个运行期 if 去判断类型&…

2026/10/10 3:18:15 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →