当前位置: 首页 > news >正文

TiUP 镜像参考指南

TiUP 镜像是 TiUP 的组件仓库,存放了一系列的组件和这些组件的元信息。镜像有两种存在形式:

  • 本地磁盘上的目录:用于服务本地的 TiUP 客户端,文档中将称之为本地镜像
  • 基于远程的磁盘目录启动的 HTTP 镜像:服务远程的 TiUP 客户端,文档中将称之为远程镜像

镜像的创建与更新

镜像可以通过以下两种方式创建:

  • 通过命令 tiup mirror init 从零生成
  • 通过命令 tiup mirror clone 从已有镜像克隆

在创建镜像之后,可以通过 tiup mirror 相关命令来给镜像添加组件或删除组件,无论是通过何种方式更新镜像,TiUP 都不会从镜像中删除任何文件,而是通过增加文件并分配新版本号的方式更新。

镜像结构

一个典型的镜像目录结构如下:

 

+ <mirror-dir> # 镜像根目录 |-- root.json # 镜像根证书 |-- {2..N}.root.json # 镜像根证书 |-- {1..N}.index.json # 组件/用户索引 |-- {1..N}.{component}.json # 组件元信息 |-- {component}-{version}-{os}-{arch}.tar.gz # 组件二进制包 |-- snapshot.json # 镜像最新快照 |-- timestamp.json # 镜像最新时间戳 |--+ commits # 镜像更新日志(可删除) |--+ commit-{ts1..tsN} |-- {N}.root.json |-- {N}.{component}.json |-- {N}.index.json |-- {component}-{version}-{os}-{arch}.tar.gz |-- snapshot.json |-- timestamp.json |--+ keys # 镜像私钥(可移动到其他位置) |-- {hash1..hashN}-root.json # 根证书私钥 |-- {hash}-index.json # 索引私钥 |-- {hash}-snapshot.json # 快照私钥 |-- {hash}-timestamp.json # 时间戳私钥

注意

  • commits 目录是在更新镜像过程中产生的日志,用于回滚镜像,磁盘空间不足时可以定期删除旧的文件夹
  • keys 文件夹中存放的私钥较敏感,建议单独妥善保管

根证书

在 TiUP 镜像中,根证书用于存放其他元信息文件的公钥,每次获取到任何元信息文件(*.json)都需要根据其文件类型(root,index,snapshot,timestamp)在当前已安装的 root.json 中找到对应的公钥,然后用公钥验证其签名是否合法。

根证书文件格式如下:

 

{ "signatures": [ # 每个元信息文件有一系列的签名,签名由该文件对应的几个私钥签出 { "keyid": "{id-of-root-key-1}", # 第一个参与签名私钥的 ID,该 ID 由私钥对应的公钥内容哈希得到 "sig": "{signature-by-root-key-1}" # 该私钥对此文件 signed 部分签名的结果 }, ... { "keyid": "{id-of-root-key-N}", # 第 N 个参与签名私钥的 ID "sig": "{signature-by-root-key-N}" # 该私钥对此文件 signed 部分签名的结果 } ], "signed": { # 被签名的部分 "_type": "root", # 该字段说明本文件的类型,root.json 的类型就是 root "expires": "{expiration-date-of-this-file}", # 该文件的过期时间,过期后客户端会拒绝此文件 "roles": { # root.json 中的 roles 用来记录对各个元文件签名的密钥 "{role:index,root,snapshot,timestamp}": { # 涉及的元文件类型包括 index, root, snapshot, timestamp "keys": { # 只有 keys 中记录的密钥签名才是合法的 "{id-of-the-key-1}": { # 用于签名 {role} 的第 1 个密钥 ID "keytype": "rsa", # 密钥类型,目前固定为 rsa "keyval": { # 密钥的 payload "public": "{public-key-content}" # 表示公钥内容 }, "scheme": "rsassa-pss-sha256" # 目前固定为 rsassa-pss-sha256 }, "{id-of-the-key-N}": { # 用于签名 {role} 的第 N 个密钥 ID "keytype": "rsa", "keyval": { "public": "{public-key-content}" }, "scheme": "rsassa-pss-sha256" } }, "threshold": {N}, # threshold 指示该元文件需要至少 N 个密钥签名 "url": "/{role}.json" # url 是指该文件的获取地址,对于 index 文件,需要在前面加上版本号,即 /{N}.index.json } }, "spec_version": "0.1.0", # 本文件遵循的规范版本,未来变更文件结构需要升级版本号,目前为 0.1.0 "version": {N} # 本文件的版本号,每次更新文件需要创建一个新的 {N+1}.root.json,并将其 version 设置为 N + 1 } }

索引

索引文件记录了镜像中所有的组件以及组件的所有者信息。

其格式如下:

 

{ "signatures": [ # 该文件的签名 { "keyid": "{id-of-index-key-1}", # 第一个参与签名的 key 的 ID "sig": "{signature-by-index-key-1}", # 该私钥对此文件 signed 部分签名的结果 }, ... { "keyid": "{id-of-root-key-N}", # 第 N 个参与签名私钥的 ID "sig": "{signature-by-root-key-N}" # 该私钥对此文件 signed 部分签名的结果 } ], "signed": { "_type": "index", # 指示该文件类型 "components": { # 组件列表 "{component1}": { # 第一个组件的名称 "hidden": {bool}, # 是否是隐藏组件 "owner": "{owner-id}", # 组件管理员 ID "standalone": {bool}, # 该组件是否可独立运行 "url": "/{component}.json", # 获取组件的地址,需要加上版本号:/{N}.{component}.json "yanked": {bool} # 该组件是否已被标记为删除 }, ... "{componentN}": { # 第 N 个组件的名称 ... }, }, "default_components": ["{component1}".."{componentN}"], # 镜像必须包含的默认组件,该字段目前固定为空(未启用) "expires": "{expiration-date-of-this-file}", # 该文件的过期时间,过期后客户端会拒绝此文件 "owners": { "{owner1}": { # 第一个属主的 ID "keys": { # 只有 keys 中记录的密钥签名才是合法的 "{id-of-the-key-1}": { # 该属主的第一个密钥 "keytype": "rsa", # 密钥类型,目前固定为 rsa "keyval": { # 密钥的 payload "public": "{public-key-content}" # 表示公钥内容 }, "scheme": "rsassa-pss-sha256" # 目前固定为 rsassa-pss-sha256 }, ... "{id-of-the-key-N}": { # 该属主的第 N 个密钥 ... } }, "name": "{owner-name}", # 该属主的名字 "threshod": {N} # 指示该属主拥有的组件必须含有至少 N 个合法签名 }, ... "{ownerN}": { # 第 N 个属主的 ID ... } } "spec_version": "0.1.0", # 本文件遵循的规范版本,未来变更文件结构需要升级版本号,目前为 0.1.0 "version": {N} # 本文件的版本号,每次更新文件需要创建一个新的 {N+1}.index.json,并将其 version 设置为 N + 1 } }

组件

组件元信息文件记录了特定组件的平台以及版本信息。

其格式如下:

 

{ "signatures": [ # 该文件的签名 { "keyid": "{id-of-index-key-1}", # 第一个参与签名的 key 的 ID "sig": "{signature-by-index-key-1}", # 该私钥对此文件 signed 部分签名的结果 }, ... { "keyid": "{id-of-root-key-N}", # 第 N 个参与签名私钥的 ID "sig": "{signature-by-root-key-N}" # 该私钥对此文件 signed 部分签名的结果 } ], "signed": { "_type": "component", # 指示该文件类型 "description": "{description-of-the-component}", # 该组件的描述信息 "expires": "{expiration-date-of-this-file}", # 该文件的过期时间,过期后客户端会拒绝此文件 "id": "{component-id}", # 该组件的 ID,具有全局唯一性 "nightly": "{nightly-cursor}", # nightly 游标,值为最新的 nightly 的版本号(如 v5.0.0-nightly-20201209) "platforms": { # 该组件支持的平台(如 darwin/amd64,linux/arm64 等) "{platform-pair-1}": { "{version-1}": { # Semantic Version 版本号(如 v1.0.0 等) "dependencies": null, # 用于约定组件之间的依赖关系,该字段尚未使用,固定为 null "entry": "{entry}", # 入口二进制文件位于 tar 包的相对路径 "hashs": { # tar 包的 checksum,我们使用 sha256 和 sha512 "sha256": "{sum-of-sha256}", "sha512": "{sum-of-sha512}", }, "length": {length-of-tar}, # tar 包的长度 "released": "{release-time}", # 该版本的 release 时间 "url": "{url-of-tar}", # tar 包的下载地址 "yanked": {bool} # 该版本是否已被禁用 } }, ... "{platform-pair-N}": { ... } }, "spec_version": "0.1.0", # 本文件遵循的规范版本,未来变更文件结构需要升级版本号,目前为 0.1.0 "version": {N} # 本文件的版本号,每次更新文件需要创建一个新的 {N+1}.{component}.json,并将其 version 设置为 N + 1 }

快照

快照文件记录了各个元文件当前的版本号。

其格式如下:

 

{ "signatures": [ # 该文件的签名 { "keyid": "{id-of-index-key-1}", # 第一个参与签名的 key 的 ID "sig": "{signature-by-index-key-1}", # 该私钥对此文件 signed 部分签名的结果 }, ... { "keyid": "{id-of-root-key-N}", # 第 N 个参与签名私钥的 ID "sig": "{signature-by-root-key-N}" # 该私钥对此文件 signed 部分签名的结果 } ], "signed": { "_type": "snapshot", # 指示该文件类型 "expires": "{expiration-date-of-this-file}", # 该文件的过期时间,过期后客户端会拒绝此文件 "meta": { # 其他元文件的信息 "/root.json": { "length": {length-of-json-file}, # root.json 的长度 "version": {version-of-json-file} # root.json 的 version }, "/index.json": { "length": {length-of-json-file}, "version": {version-of-json-file} }, "/{component-1}.json": { "length": {length-of-json-file}, "version": {version-of-json-file} }, ... "/{component-N}.json": { ... } }, "spec_version": "0.1.0", # 本文件遵循的规范版本,未来变更文件结构需要升级版本号,目前为 0.1.0 "version": 0 # 本文件的版本号,固定为 0 }

时间戳

时间戳文件记录了当前快照 checksum。

其文件格式如下:

 

{ "signatures": [ # 该文件的签名 { "keyid": "{id-of-index-key-1}", # 第一个参与签名的 key 的 ID "sig": "{signature-by-index-key-1}", # 该私钥对此文件 signed 部分签名的结果 }, ... { "keyid": "{id-of-root-key-N}", # 第 N 个参与签名私钥的 ID "sig": "{signature-by-root-key-N}" # 该私钥对此文件 signed 部分签名的结果 } ], "signed": { "_type": "timestamp", # 指示该文件类型 "expires": "{expiration-date-of-this-file}", # 该文件的过期时间,过期后客户端会拒绝此文件 "meta": { # snapshot.json 的信息 "/snapshot.json": { "hashes": { "sha256": "{sum-of-sha256}" # snapshot.json 的 sha256 }, "length": {length-of-json-file} # snapshot.json 的长度 } }, "spec_version": "0.1.0", # 本文件遵循的规范版本,未来变更文件结构需要升级版本号,目前为 0.1.0 "version": {N} # 本文件的版本号,每次更新文件需要覆盖 timestamp.json,并将其 version 设置为 N + 1

客户端工作流程

客户端通过以下逻辑保证从镜像下载到的文件是安全的:

  • 客户端安装时随 binary 附带了一个 root.json
  • 客户端运行时以已有的 root.json 为基础,做如下操作:
    1. 获取 root.json 中的 version,记为 N
    2. 向镜像请求 {N+1}.root.json,若成功,使用 root.json 中记录的公钥验证该文件是否合法
  • 向镜像请求 timestamp.json,并使用 root.json 中记录的公钥验证该文件是否合法
  • 检查 timestamp.json 中记录的 snapshot.json 的 checksum 和本地的 snapshot.json 的 checksum 是否吻合
    • 若不吻合,则向镜像请求最新的 snapshot.json 并使用 root.json 中记录的公钥验证该文件是否合法
  • 对于 index.json 文件,从 snapshot.json 中获取其版本号 N,并请求 {N}.index.json,然后使用 root.json 中记录的公钥验证该文件是否合法
  • 对于组件(如 tidb.json,tikv.json),从 snapshot.json 中获取其版本号 N,并请求 {N}.{component}.json,然后使用 index.json 中记录的公钥验证该文件是否合法
  • 对于组件 tar 文件,从 {component}.json 中获取其 url 及 checksum,请求 url 得到 tar 包,并验证 checksum 是否正确

相关文章:

  • 鹏城AI靶场助力大规模高质量中文语料数据集安全开放
  • 安装node, 配置npm全局安装位置,安装Vue.
  • 神经网络理论及应用答案,神经网络理论名词解释
  • 国产香氛品牌别样的生意经
  • Java-基于SSM的健身后台管理系统
  • 【CCIE 实验】BGP 13条选路原则实验
  • 购买发票自动化软件(或者文档管理系统)需要注意的问题
  • 磁盘被未知资源耗尽lsof -n|grep deleted
  • 图观 | 快速评估图数据库何时适合使用?
  • Redis主从集群
  • 瑞吉外卖git
  • NAS媒体库资源归集整理工具nas-tools
  • ECCV 2022 | MVDG:一种用于域泛化的统一多视图框架
  • Gin源码之gin.Engine结构体及其方法
  • 神经系统ct与mri影像解读,神经系统影像学检查
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • javascript从右向左截取指定位数字符的3种方法
  • java第三方包学习之lombok
  • Nodejs和JavaWeb协助开发
  • ReactNativeweexDeviceOne对比
  • 分享几个不错的工具
  • 给github项目添加CI badge
  • 让你的分享飞起来——极光推出社会化分享组件
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 因为阿里,他们成了“杭漂”
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (Matlab)使用竞争神经网络实现数据聚类
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)计算机毕业设计大学生兼职系统
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)平衡树
  • .libPaths()设置包加载目录
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .net core webapi 大文件上传到wwwroot文件夹
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET实现之(自动更新)
  • @requestBody写与不写的情况
  • @Valid和@NotNull字段校验使用
  • [CC2642r1] ble5 stacks 蓝牙协议栈 介绍和理解
  • [EFI]DELL XPS13 9360电脑 Hackintosh 黑苹果efi引导文件
  • [Go WebSocket] 多房间的聊天室(三)自动清理无人房间
  • [hdu 4405] Aeroplane chess [概率DP 期望]
  • [HeMIM]Cl,[AeMIM]Br,[CeEIM]Cl,([HO-PECH-MIM]Cl,[HOOC-PECH-MIM]Cl改性酚醛树脂
  • [Linux] 进程间通信基础