> 基于 Ceph 官方文档整理 | 文档版本:**Tentacle v20.2.4** | 抓取日期:2026-09-17 | 源文:ceph/ceph@v20.2.4 `doc/radosgw/` > 官网入口:https://docs.ceph.com/en/tentacle/radosgw/ # 09 · RGW 对象存储篇(一):核心架构、部署与运维 --- ## 本册导读 本册是 **RGW 对象存储四册中的第一册**,聚焦「RGW 是什么、怎么跑起来、怎么管」。 | 分册 | 主题 | 覆盖内容(对应 `doc/radosgw/` 页面) | |---|---|---| | **第 09 册(本册)** | 核心架构、部署与运维 | `index`, `frontends`, `pools`, `placement`, `layout`, `config-ref`, `admin`, `adminops`, `account`, `multitenancy`, `nfs`, `metrics`, `troubleshooting` | | 第 10 册 | 多站点(Multisite)与数据同步 | `multisite`, `multisite-sync-policy`, `zone-features`, `sync-modules`, `cloud-sync-module`, `elastic-sync-module`, `archive-sync-module`, `orphans`, `cloud-transition`, `cloud-restore` | | 第 11 册 | 数据面 API 与安全体系 | `s3`, `swift`, `iam`, `STS`, `STSLite`, `role`, `keycloak`, `oidc`, `session-tags`, `bucketpolicy`, `encryption`, `barbican`, `vault`, `kmip`, `opa`, `ldap-auth`, `keystone`, `mfa` | | 第 12 册 | 高级特性与扩展能力 | `notifications`, `s3-notification-compatibility`, `bucket_logging`, `compression`, `s3select`, `lua-scripting`, `rgw-cache`, `d3n_datacache`, `dynamicresharding`, `qat-accel`, `uadk-accel`, `api` | > 💡 补充:上表的「四册分工」是本手册的编排方案,Ceph 官方并未将 `doc/radosgw/` 划分为四册。官方 `index.rst` 的 toctree 是一个扁平的 50+ 页面列表,本手册按其主题相关性做了归组,页面→分册的映射以 `index.rst` 中真实的 toctree 条目为准。 **阅读建议**:本册是其余三册的基础。建议先读完第二、三、四章(架构/数据布局/存储池)建立心智模型,再读第六、七章(管理命令与管理 API)作为日常操作手册,第十二章(配置参考)作为查阅字典。 --- ## 一、RGW 是什么 ### 1.1 定位 :term:`Ceph Object Gateway`(RGW,守护进程名 `radosgw`)是构建在 `librados` 之上的**对象存储接口层**。它在应用与 Ceph 存储集群之间提供了一层 RESTful 网关。 官方文档对 RGW 的原始定义(直译): > Ceph 对象网关是一个构建在 `librados` 之上的对象存储接口,为应用与 Ceph 存储集群之间提供 RESTful 网关。Ceph 对象存储支持两种接口: > 1. **S3 兼容**:提供与 Amazon S3 RESTful API 的很大一个子集兼容的对象存储功能。 > 2. **Swift 兼容**:提供与 OpenStack Swift API 的很大一个子集兼容的对象存储功能。 > > Ceph 对象存储使用 Ceph 对象网关守护进程(`radosgw`),这是一个为与 Ceph 存储集群交互而设计的 HTTP 服务器。 关键事实(全部来自 `index.rst`): | 事实 | 说明 | |---|---| | 底层依赖 | `librados`,不是独立的存储引擎 | | 守护进程 | `radosgw`(HTTP 服务器) | | 兼容接口 | Amazon S3 RESTful API 的**大子集**、OpenStack Swift API 的**大子集** | | 用户体系 | **自带**用户管理(独立于 Ceph 集群的 `client.*` 认证) | | 命名空间 | **S3 API 与 Swift API 共享同一个命名空间**——用一种 API 写入,可用另一种 API 读出 | | 与 CephFS/RBD 的关系 | 可以用**同一个** Ceph 存储集群同时承载 Ceph 文件系统、Ceph 块设备客户端与 RGW 的数据 | | MDS 依赖 | **不使用** Ceph Metadata Server(官方 note 明确强调:Ceph Object Storage does **NOT** use the Ceph Metadata Server) | 官方给出的分层示意图(`index.rst` 的 ditaa,此处转为文本): ```text +------------------------+ +------------------------+ | S3 compatible API | | Swift compatible API | +------------------------+-+------------------------+ | radosgw | +---------------------------------------------------+ | librados | +------------------------+-+------------------------+ | OSDs | | Monitors | +------------------------+ +------------------------+ ``` ### 1.2 S3 / Swift 双接口与共享命名空间 - **S3 接口**:面向使用 AWS S3 SDK 的应用。认证使用 access key / secret key 的签名机制。 - **Swift 接口**:面向 OpenStack Swift 生态。认证使用 Swift 的账号/用户/密钥机制,在 RGW 内部体现为 **subuser**(见第六章)。 - **共享命名空间**:两 API 共享同一份 bucket/object 数据。Swift 的 *container* 在 RGW 中就是 S3 的 *bucket*,文档里两者互换使用(`layout.rst`:「Swift 所谓的 *container* 与 S3 术语 *bucket* 可以互换使用,因此我们说 RGW 的 bucket 实现了 Swift container」)。 ### 1.3 与原生 AWS S3 的能力差异(本册源文可确证的部分) > ⚠️ 本册范围内的官方文档**没有**给出一份完整的「RGW vs AWS S3 差异清单」。以下是本册所读源文中**明确提到**的差异点,其余差异官方文档未在本册范围内说明(将在第 11 册展开)。 | 差异点 | 官方文档原文/含义 | 出处 | |---|---|---| | API 只是「大子集」 | 「compatible with a *large subset* of the Amazon S3 RESTful API」——并非 100% 兼容 | `index.rst` | | Storage Class 命名 | 使用 AWS S3 SDK(如 `boto3`)时,storage class 名称**必须**与 AWS S3 提供的名称一致,否则 SDK 会丢弃请求并抛异常 | `placement.rst` | | `GLACIER` 前缀的坑 | 部分 S3 客户端/库对名为或以 `GLACIER` 为前缀的 storage class 有 AWS 特有行为的预期,用于 Ceph RGW 时会失败 | `placement.rst` | | Bucket 命名规则 | 可通过 `rgw_relaxed_s3_bucket_names` 放宽 S3 bucket 命名限制(例如 Swift container 名含下划线时不被 S3 规则接受) | `nfs.rst`, `config-ref.rst` | | 多租户 | 原生 S3 API **不处理**多租户,而 radosgw 的实现处理——这在签名 URL 与 public read ACL 场景下带来额外复杂度 | `multitenancy.rst` | | NFS 语义限制 | 通过 NFS 导出时:不支持链接(含 symlink)、不支持 NFS ACL、目录不可移动/重命名、只支持完整顺序写 | `nfs.rst` | 官方建议的 storage class 命名(`placement.rst`):优先使用 `INTELLIGENT-TIERING`、`STANDARD_IA`、`REDUCED_REDUNDANCY`、`ONEZONE_IA`;自定义名如 `CHEAPNDEEP` 虽然 Ceph 接受,但部分客户端/库可能不接受。 ### 1.4 适用场景与不适用场景 > 💡 补充:官方文档在本册范围内**没有**列出适用/不适用场景清单。以下为基于本册源文事实(1.1/1.2/1.3 节 + NFS 限制 + 顺序写限制)的归纳,非官方原文。 **适用场景** | 场景 | 依据 | |---|---| | 需要 S3/Swift 兼容 API 的私有云/自建对象存储 | 双接口 + 共享命名空间(`index.rst`) | | 同一套 Ceph 集群要同时服务块、文件、对象 | 「single Ceph Storage cluster to store data from CephFS and Ceph block device clients」(`index.rst`) | | 需要按业务/成本分层存储 | placement target + storage class + S3 Lifecycle `Transition`(`placement.rst`) | | 多业务方共用且 bucket 名易冲突 | 多租户 `tenant`(`multitenancy.rst`)、账号 `account`(`account.rst`) | | 需要细粒度配额与限流 | quota(user/bucket/account)、ratelimit(`admin.rst`, `adminops.rst`) | | 需要把对象存储挂成文件系统给遗留应用 | NFSv4 导出(`nfs.rst`) | | 需要 S3 兼容的监控指标 | RGW op metrics → Prometheus(`metrics.rst`) | **不适用场景(或需谨慎评估)** | 场景 | 原因(依据) | |---|---| | 期望 100% AWS S3 语义/行为 | 官方明确只兼容「large subset」(`index.rst`) | | 需要 POSIX 完整语义的文件访问 | NFS 导出不支持链接、不支持 NFS ACL、目录不可重命名、只支持顺序写(`nfs.rst`) | | 作为数据库/随机读写块设备使用 | 非对象存储设计目标;本册范围内文档未明确说明,属常识性判断 | | 依赖 MDS 的元数据服务 | RGW 明确不使用 MDS(`index.rst`) | --- ## 二、架构 ### 2.1 RGW 在 Ceph 中的位置 RGW 是 **Ceph 客户端**,不是 Ceph 集群的核心组件: - 它对上暴露 HTTP/REST(S3、Swift、Admin、STS、IAM、Notifications 等,由 `rgw_enable_apis` 控制,默认值见第十二章); - 它对下通过 `librados` 与 MON / OSD 通信; - 它**不经过** Ceph Metadata Server(MDS); - 它自带用户管理与元数据(user、bucket、bucket.instance、roles、account 等),这些元数据本身也存放在 RADOS 的专用 pool 中(见第三、四章)。 ### 2.2 RGW 与 RADOS 的关系 RGW 把「S3/Swift 的对象语义」翻译成「RADOS 的 pool + object + omap + xattr」: | RGW 概念 | 落到 RADOS | |---|---| | user | 一个 RADOS 对象,名字为 ``,位于 pool `default.rgw.meta` 的 `users.uid` namespace | | bucket(名字→实例的映射) | pool `default.rgw.meta` 的 `root` namespace | | bucket index | 默认每个 bucket 一个 RADOS 对象 `.dir.`,位于 `default.rgw.buckets.index`;omap 存 key-value 映射 | | object data | 一个或多个 RADOS 对象,位于 `default.rgw.buckets.data`,对象名 `_` | | 用户的 bucket 列表 | 对象 `.buckets` 的 omap,位于 `default.rgw.meta` 的 `users.uid` namespace | | 不完整 multipart 的元数据 | `data_extra_pool`,默认 `default.rgw.buckets.non-ec` | ### 2.3 zone / zonegroup / realm / period 概念 > 本册范围内,`pools.rst` 与 `placement.rst` 只涉及 **zone** 与 **zonegroup**;`realm` 与 `period` 属多站点(Multisite)范畴,详见第 10 册(源文 `multisite.rst`)。本节仅就本册源文可确证部分说明。 | 概念 | 本册源文中的定义/作用 | |---|---| | **zone** | 一组具体的 RADOS pool 及其用途映射。每个 zone 的 pool 名遵循 `{zone-name}.pool-name` 命名约定。默认自动创建一个名为 `default` 的 zone,其 pool 名以 `default.rgw.` 开头。zone 配置里包含 domain_root、placement_pools 等 | | **zonegroup** | 包含一组 zone;其配置中持有 **placement targets 列表**(初始有一个名为 `default-placement` 的 target),以及 `default_placement`、`api_name`、`hostnames` 等 | | **realm** | 多站点顶层容器。本册源文只在 `placement.rst` 的 note 中提及:「如果你为 multisite 创建了 realm,zone/zonegroup 的改动需要 `radosgw-admin period update --commit` 提交后才生效」 | | **period** | realm 的配置版本/纪元。同上,通过 `radosgw-admin period update --commit` 提交变更 | **默认 zone(非多站点)下的行为**(`placement.rst` note): ```text 如果没有做过 Multisite 配置,系统会为你自动创建 default zone 与 zonegroup, 且对 zone/zonegroup 的修改要等到 Ceph 对象网关重启后才会生效。 如果创建了用于 multisite 的 realm,则 zone/zonegroup 的修改在 `radosgw-admin period update --commit` 提交后生效。 ``` **zone/zonegroup 配置的查看**: ```bash radosgw-admin zonegroup get radosgw-admin zone get ``` `zonegroup get` 输出中的 placement 部分: ```json { "id": "ab01123f-e0df-4f29-9d71-b44888d67cd5", "name": "default", "api_name": "default", "placement_targets": [ { "name": "default-placement", "tags": [], "storage_classes": [ "STANDARD" ] } ], "default_placement": "default-placement" } ``` `zone get` 输出中的 placement 部分: ```json { "id": "557cdcee-3aae-4e9e-85c7-2f86f5eddb1f", "name": "default", "domain_root": "default.rgw.meta:root", "placement_pools": [ { "key": "default-placement", "val": { "index_pool": "default.rgw.buckets.index", "storage_classes": { "STANDARD": { "data_pool": "default.rgw.buckets.data" } }, "data_extra_pool": "default.rgw.buckets.non-ec", "index_type": 0, "inline_data": true } } ] } ``` ### 2.4 相关配置项(zone/zonegroup/realm 定位) | 配置项 | 类型 | 默认值(默认值取自 src/common/options/*.yaml.in @ v20.2.4) | 含义 | |---|---|---|---| | `rgw_zone` | str | (无默认值) | Zone name | | `rgw_zonegroup` | str | (无默认值) | Zonegroup name | | `rgw_realm` | str | (无默认值) | 网关实例所属 realm 名。若未设置 realm,可用 `radosgw-admin realm default` 配置一个集群级默认值 | > 引自:[Ceph Object Gateway](https://docs.ceph.com/en/tentacle/radosgw/) --- ## 三、数据布局(Data Layout in RADOS) 来源:`layout.rst`(全文 8KB,本节逐节展开)。 ### 3.1 概念视图:三类信息 RADOS 只认识 pool、object、xattr 和 omap。但在概念上,RGW 维护**三类**信息: | 类别 | 说明 | |---|---| | **metadata(元数据)** | 用户、bucket、bucket instance、角色、账号、OTP、group、topic 等 | | **bucket index(桶索引)** | 一种特殊元数据,单独存放;是挂在 RADOS 对象上的 key-value map | | **data(载荷数据)** | 每个 RGW object 对应一个或多个 RADOS object | > **Omap 定义(源文脚注 [1])**:Omap 是关联在某个对象上的 key-value 存储,类似于 POSIX 文件上的扩展属性(XATTR)。对象的 omap 与其 payload 数据**不物理同置**,其具体实现对 RGW 守护进程不可见也不重要。 ### 3.2 Metadata(元数据) 查看当前支持的元数据类型: ```bash radosgw-admin metadata list ``` 输出(2025 年 4 月的类型列表,源文原文): ```json [ "account", "bucket", "bucket.instance", "group", "otp", "roles", "topic", "user" ] ``` 常用检查命令(源文原文): ```bash radosgw-admin metadata list radosgw-admin metadata list bucket radosgw-admin metadata list bucket.instance radosgw-admin metadata list user radosgw-admin metadata get bucket: radosgw-admin metadata get bucket.instance:: radosgw-admin metadata get user: # get or set ``` 变量含义(源文原文): | 变量 | 含义 | |---|---| | `_user_` | 持有用户信息(Holds user information) | | `_bucket_` | 持有 bucket 名 → bucket instance id 的映射 | | `_bucket.instance_` | 持有 bucket instance 信息 | 要点: - **每条元数据条目保存在单个 RADOS 对象上**。 - **元数据没有索引**。列举某个 metadata section 时,是对所在 pool 执行一次 RADOS `pgls` 操作。 - **历史坑(脚注 [2])**:Dumpling 版本之前不存在 `bucket.instance` 元数据,其信息包含在 `bucket` 元数据中。老集群中可能遇到这种 bucket。 ### 3.3 Bucket Index(桶索引) - bucket index 是一种**不同种类**的元数据,单独保存。 - 它保存的是**挂在 RADOS 对象上的 key-value map**。 - **默认每个 bucket 一个 RADOS 对象**;自 **Hammer** 版本起可以把这个 map **分片(shard)** 到多个 RADOS 对象上。 - map 本身存放在 **omap** 中,与每个 RADOS 对象关联。 - **omap 的 key** = 对象名; - **omap 的 value** = 该对象的基本元数据(即 list bucket 时显示的那些元数据)。 - 每个 omap 还有一个 **header**,RGW 在 header 里保存一些 **bucket 账目元数据**(对象数、总大小等)。 - bucket index 中还保存**其它信息**,位于**其它 key namespace**: - bucket index log(bilog); - 版本化(versioned)对象的额外信息。 ### 3.4 Data(对象数据) 每个 RGW object 的数据存放在**一个或多个** RADOS object 中。 #### 对象查找路径(Object Lookup Path) 访问 S3/Swift 对象时,REST API 带给 RGW 三个参数: | 参数 | 说明 | |---|---| | account 信息 | S3 的 access key 或 Swift 的 account name。**目前 RGW 只用 account 信息来查 user ID 和做访问控制** | | bucket / container 名 | 用于寻址 | | object 名(key) | 用于寻址 | > **只有 bucket 名和 object key 用于在一个 pool 中寻址对象。** > RGW 中的 user ID 就是一个字符串,通常就是来自用户凭据的真实用户名,而不是哈希或映射后的标识符。 完整查找链: ```text 1) user 记录 → pool default.rgw.meta, namespace users.uid, 对象名 2) bucket 记录 → pool default.rgw.meta, namespace root (读取该记录以获得所谓 marker,marker 充当 bucket ID) 3) 对象数据 → pool default.rgw.buckets.data RADOS 对象名 = _ 例:default.7593.4_image.png marker = default.7593.4,key = image.png ``` 关于分隔符(源文原文要点): - 这些拼起来的名字**不会被解析**,只是原样下传给 RADOS,因此**分隔符的选择不重要、也不会产生歧义**。 - 同样因为不解析,**对象名(key)中允许出现斜杠 `/`**。 多数据池与扩展(源文原文): > 可以创建多个 data pool,并让不同用户的 bucket 默认创建在不同的 RADOS pool 中,从而提供所需的扩展能力。这些 pool 的布局与命名由 'policy' 设置控制。 #### HEAD 与 tail 对象 - 一个 RGW object 可由**多个 RADOS object** 组成,**第一个**是 `HEAD`。 - `HEAD` 包含的元数据(存放在 **xattrs** 中): - manifest(清单,描述该 RGW object 如何分布到各 RADOS object 上) - ACLs - content type - ETag - 用户自定义元数据 - `HEAD` 对象还可以**内联(inline)最多 `rgw_max_chunk_size` 大小的对象数据**,以提高效率与原子性。 `rgw_max_chunk_size` 官方完整说明(默认值取自 src/common/options/rgw.yaml.in @ v20.2.4): | 配置项 | 类型 | 默认值 | 说明 | |---|---|---|---| | `rgw_max_chunk_size` | size | `4_M` | chunk size 是 RGW 访问 RADOS 对象时发给 OSD 的请求大小。RGW 的读写操作单次请求永远不会超过这个量。它也定义了 RGW HEAD 对象的大小,因为 head 操作需要是原子的,超过这个量就需要多于一次操作。当 RGW 对象写入**默认 storage class** 时,最多会有这么多的载荷数据与元数据一起存在 head 对象中。注意:当把 RGW 对象写入**非默认 storage class** 时,HEAD RADOS 对象**始终**存放在默认 storage class 的 pool 中,但**不会**内联载荷数据。 | 官方给出的分层(tiering)策略(源文原文要点): > 这带来一个方便的分层策略:index pool 必须是副本池(不能是 EC),应放在快速 SSD OSD 上。当 RGW 对象混合了小/热对象与更大、温/冷的对象(如视频文件)时,较大的对象会自动落到 `buckets.data` pool,后者可以是 EC 池和/或更慢的介质(HDD 或 QLC SSD)。 ### 3.5 multipart 与分片(sharding)——本册可确证部分 | 主题 | 本册源文可确证内容 | |---|---| | **bucket index 分片** | 自 Hammer 起支持把 bucket index map 分片到多个 RADOS 对象;分片时每个 shard 在 marker 之后追加 shard index。相关配置:`rgw_override_bucket_index_max_shards`(默认 `0`,见第十二章);动态分片另见 `dynamicresharding.rst`(第 12 册) | | **multipart 的 RADOS 布局** | 对象名示例:`default.7593.4__shadow_.488urDFerTYXavx4yAd-Op8mxehnvTI_1`(`layout.rst` 附录) | | **不完整 multipart 的元数据** | 存放在 `data_extra_pool`,zone 默认值为 `default.rgw.buckets.non-ec`(`placement.rst`:「`data_extra_pool` name for metadata about incomplete multipart uploads」) | | **multipart 最小分片大小** | `rgw_multipart_min_part_size`,默认 `5_M`(见第十二章) | | **multipart 计数一致性检查** | Admin Ops API `Check Bucket Index` 的 `check-objects` 参数用于「Check multipart object accounting」,且必须同时 `fix=True` 才生效(见第七章) | > 💡 补充:`layout.rst` 并未系统讲述 multipart upload 的完整 RADOS 布局(如 `shadow` 对象的切分规则、`rgw_obj_stripe_size` 与 tail 的关系)。官方源文只给出了上面这些零散事实点,未说明的部分本手册不臆测。 ### 3.6 Bucket 与 Object 列举(Listing) | 列举对象 | 实现方式 | |---|---| | 某用户拥有的 bucket 列表 | 对象 `.buckets`(例如 `foo.buckets`)的 **omap**,位于 pool `default.rgw.meta`、namespace `users.uid`。在列举 bucket、更新 bucket 内容、更新与获取 bucket 统计(如 quota)时访问这些对象 | | 某 bucket 中的对象列表 | 走 **bucket index**(见 3.3);index 对象默认命名 `.dir.`,位于 pool `default.rgw.buckets.index` | - bucket 列表的 omap 值结构:见用户可见的编码类 **`cls_user_bucket_entry`** 及其嵌套类 **`cls_user_bucket`**。 - 这些列举与 pool 名为 `.rgw` 中的 bucket 保持一致性(源文:「These listings are kept consistent with buckets in the pool named `.rgw`」)。 ### 3.7 附录:已知 pool 与对象命名速查(源文原文汇总) ```text .rgw.root Region, zone, and global information records, one per object. .rgw.control notify. .rgw.meta Multiple namespaces with different kinds of metadata: namespace: root .bucket.meta.: # see put_bucket_instance_info() The tenant is used to disambiguate buckets, but not bucket instances. Example: .bucket.meta.prodtx:test%25star:default.84099.6 .bucket.meta.testcont:default.4126.1 .bucket.meta.prodtx:testcont:default.84099.4 prodtx/testcont prodtx/test%25star testcont namespace: users.uid Contains *both* per-user information (RGWUserInfo) in "" objects and per-user lists of buckets in omaps of ".buckets" objects. The "" may contain the tenant if non-empty, for example: prodtx$prodt test2.buckets prodtx$prodt.buckets test2 namespace: users.email Unimportant namespace: users.keys example: 47UA98JSTJZ9YAN3OS3O This allows radosgw to look up users by their access keys during authentication. namespace: users.swift test:tester .rgw.buckets.index Objects are named .dir.: each contains a bucket index. If the index is sharded, each shard appends the shard index after the marker. .rgw.buckets.data example: default.7593.4__shadow_.488urDFerTYXavx4yAd-Op8mxehnvTI_1 _ ``` **marker 格式**(源文原文):marker 示例为 `default.16004.1` 或 `default.7593.4`。当前格式为 `..`。但 marker 一旦生成就不再被解析,所以其格式未来可自由变化。 > 引自:[Data Layout in RADOS](https://docs.ceph.com/en/tentacle/radosgw/layout/) --- ## 四、存储池与放置策略 ### 4.1 RGW 用到的 pool > 来源:`pools.rst` + `layout.rst` 附录 + `placement.rst`。 > 重要提示(源文原文):Ceph 对象网关为其各种存储需求使用若干 pool,**这些 pool 列在 Zone 对象中(见 `radosgw-admin zone get`)**。系统会自动创建一个名为 `default` 的 zone,其 pool 名以 `default.rgw.` 开头;而 Multisite 配置会有多个 zone。 #### 4.1.1 核心 pool 表 | pool 名(以 zone 名为 `default` 为例) | 用途 | 建议 PG | |---|---|---| | `.rgw.root` | Region、zone 以及 global 信息记录,每个对象一条 | 文档未明确(初始按 `osd pool default pg num` 创建,见下) | | `default.rgw.control` | RGW 控制面(对象形如 `notify.`),用于跨 RGW 通信 | 文档未明确 | | `default.rgw.meta` | 多 namespace 元数据池,含 `root` / `users.uid` / `users.email` / `users.keys` / `users.swift` | 文档未明确 | | `default.rgw.log` | 日志(源文仅列出名字,未展开用途) | 文档未明确 | | `default.rgw.buckets.index` | **bucket index**。对象命名 `.dir.`;分片时追加 shard index。**必须**是副本池(不能 EC),且应放在快速 SSD OSD 上(`layout.rst` 明示) | 文档未明确;源文提示该池「需要额外调优」 | | `default.rgw.buckets.data` | **对象数据**。对象命名 `_`。可以是 EC 池和/或更慢介质(HDD / QLC SSD) | 文档未明确;源文提示该池「需要额外调优」 | | `default.rgw.buckets.non-ec` | **data_extra_pool**:存放**未完成 multipart 上传**的元数据;`zone get` 中 `default-placement` 的默认值 | 文档未明确 | > ⚠️ **关于「建议 PG」**:本册范围内的官方文档**没有**给出任何 pool 的 PG 数量建议数值,全部标注「文档未明确」。文档只说明了创建时机与默认值来源,见 4.1.2。 > > 💡 补充:源文 `pools.rst` 只列出 `.rgw.root` 与 5 个 `.rgw.*` pool 共 6 个名字,`default.rgw.buckets.non-ec` 来自 `placement.rst` 的 `zone get` 示例。完整的 zone 定义中还有**更多** pool 条目(官方原文:「The zone definitions list several more pools than that」),但本册范围(`pools.rst`/`layout.rst`/`placement.rst`)未逐一列出,故不在此表中杜撰。 #### 4.1.2 pool 的创建与调优(源文原文) > 当 `radosgw` 首次尝试操作一个尚不存在的 zone pool 时,它会用 `osd pool default pg num` 和 `osd pool default pgp num` 的默认值来创建该 pool。这些默认值对某些 pool 是够用的,但**其它 pool(尤其是 `placement_pools` 中列出的 bucket index 与 data 池)需要额外的调优**。 相关配置项(默认值取自 src/common/options/*.yaml.in @ v20.2.4): | 配置项 | 类型 | 默认值 | 说明 | |---|---|---|---| | `osd pool default pg num` | 文档未在本册范围内查证 | 文档未明确 | pool 创建时的默认 PG 数 | | `osd pool default pgp num` | 文档未在本册范围内查证 | 文档未明确 | pool 创建时的默认 PGP 数 | #### 4.1.3 Pool Namespaces(自 Luminous 起) pool 名遵循 `{zone-name}.pool-name` 约定。例如一个名为 `us-east` 的 zone 会有: ```text .rgw.root us-east.rgw.control us-east.rgw.meta us-east.rgw.log us-east.rgw.buckets.index us-east.rgw.buckets.data ``` **许多 pool 条目通过 rados namespace 被合并**。例如以下 pool 条目其实都是 `us-east.rgw.meta` pool 的 namespace: ```json "user_keys_pool": "us-east.rgw.meta:users.keys", "user_email_pool": "us-east.rgw.meta:users.email", "user_swift_pool": "us-east.rgw.meta:users.swift", "user_uid_pool": "us-east.rgw.meta:users.uid", ``` ### 4.2 Placement Target(放置目标) > versionadded:: Jewel **定义**:placement target 控制**哪些 pool 与某个特定 bucket 关联**。 | 要点 | 说明 | |---|---| | 选择时机 | **在 bucket 创建时**选定 | | 可否修改 | **不可修改**("A bucket's placement target is selected on creation, and cannot be modified.") | | 查看方式 | `radosgw-admin bucket stats` 会显示其 `placement_rule` | | zonegroup 侧 | 持有 placement target 列表,初始有一个名为 **`default-placement`** 的 target | | zone 侧 | 把 zonegroup 中的每个 placement target 名字映射到本地存储。包含:`index_pool`(bucket index)、`data_extra_pool`(未完成 multipart 元数据)、以及**每个 storage class 一个 `data_pool`** | ### 4.3 Storage Class(存储类) > versionadded:: Nautilus **定义**:storage class 指定**对象数据的放置位置**。S3 Bucket Lifecycle(LC)规则可以自动化对象在 storage class 之间的转换(Transition)。 | 要点 | 说明 | |---|---| | 定义层级 | 以 placement target 为单位定义 | | zonegroup 侧 | 每个 placement target 列出其可用 storage class,初始有一个名为 **`STANDARD`** 的 class | | zone 侧 | 负责为 zonegroup 的每个 storage class 提供一个 `data_pool` 名 | ### 4.4 新增 placement target / storage class 的操作 **新增名为 `temporary` 的 placement target**——先加到 zonegroup: ```bash radosgw-admin zonegroup placement add \ --rgw-zonegroup default \ --placement-id temporary ``` 然后为该 target 提供 zone 侧的 placement 信息: ```bash radosgw-admin zone placement add \ --rgw-zone default \ --placement-id temporary \ --data-pool default.rgw.temporary.data \ --index-pool default.rgw.temporary.index \ --data-extra-pool default.rgw.temporary.non-ec ``` **新增名为 `STANDARD_IA` 的 storage class 到 `default-placement`**——先加到 zonegroup: ```bash radosgw-admin zonegroup placement add \ --rgw-zonegroup default \ --placement-id default-placement \ --storage-class STANDARD_IA ``` 然后提供 zone 侧该 storage class 的 placement 信息(示例中还指定了压缩): ```bash radosgw-admin zone placement add \ --rgw-zone default \ --placement-id default-placement \ --storage-class STANDARD_IA \ --data-pool default.rgw.glacier.data \ --compression lz4 ``` #### inline data 的说明(官方 note 全文要点) `zone placement add` / `zone placement modify` 支持 `--placement-inline-data=false`: | 行为 | 说明 | |---|---| | 默认(inline) | RGW 把对象的**第一个数据块**与 XATTR 元数据一起存放在 RADOS `HEAD` 对象里。**优势**:读写工作负载下,首块数据可随对象元数据在一次 librados 调用中取回/写入 | | 非 inline | 当 **BlueStore DB 位于比 bucket data 更快的存储**上时,对 **RGW 客户端 delete 请求**有性能优势——省去了处理客户端请求时同步访问慢设备。此时被删除对象的数据由**后台 GC 异步**清除 | | 限制 | **只有写入默认 storage class 时才会 inline**;写入**非默认** storage class 时**永不** inline | ### 4.5 定制放置(Customizing Placement) #### 4.5.1 Default Placement 新建 bucket 默认使用 zonegroup 的 `default_placement` target。可用以下命令修改: ```bash radosgw-admin zonegroup placement default \ --rgw-zonegroup default \ --placement-id new-placement ``` #### 4.5.2 User Placement 用户可以用其 user info 中**非空**的 `default_placement` 字段覆盖 zonegroup 的默认 placement target;同理 `default_storage_class` 可覆盖默认施加到对象上的 `STANDARD`。 ```bash $ radosgw-admin user info --uid testid { ... "default_placement": "", "default_storage_class": "", "placement_tags": [], ... } ``` **tags 的访问控制作用**:如果 zonegroup 的 placement target 含有任何 `tags`,那么**除非**用户的 user info 中 `placement_tags` 字段至少含有一个匹配的 tag,否则该用户无法用该 placement target 创建 bucket。这可用于限制对某类存储的访问。 直接修改这些字段: ```bash radosgw-admin user modify \ --uid \ --placement-id \ --storage-class \ --tags ``` #### 4.5.3 S3 Bucket Placement 用 S3 协议创建 bucket 时,可通过 **LocationConstraint** 提供 placement target,覆盖用户与 zonegroup 的默认值。 - 常规情况下 LocationConstraint 必须匹配 zonegroup 的 `api_name`: ```xml default ``` - 在 `api_name` 后加冒号即可指定自定义 placement target: ```xml default:new-placement ``` #### 4.5.4 Swift Bucket Placement 用 Swift 协议创建 bucket 时,通过 HTTP header **`X-Storage-Policy`** 提供 placement target: ```http X-Storage-Policy: new-placement ``` ### 4.6 使用 Storage Class | 场景 | 做法 | |---|---| | 默认 | 所有 placement target 都有一个 `STANDARD` storage class,默认施加到新对象上 | | 用户级覆盖 | 用户用其 `default_storage_class` 覆盖 | | 单对象指定 | 在请求的 HTTP header 中给出 storage class 名:**S3 用 `X-Amz-Storage-Class`**,**Swift 用 `X-Object-Storage-Class`** | | 自动流转 | 用 S3 Object Lifecycle Management 的 `Transition` action 在 storage class 间搬移对象数据 | **与 AWS SDK 的兼容性警告(源文原文要点)**: 1. 使用 `boto3` 这类 AWS S3 SDK 时,**storage class 名称必须匹配 AWS S3 提供的名称**,否则 SDK 会丢弃请求并抛异常。 2. 部分 S3 客户端与库对名为或以 **`GLACIER`** 为前缀的 storage class 有 AWS 特有行为的预期,用在 Ceph RGW 上会失败。 3. 官方建议改用:`INTELLIGENT-TIERING`、`STANDARD_IA`、`REDUCED_REDUNDANCY`、`ONEZONE_IA`。 4. 自定义名(如 `CHEAPNDEEP`)Ceph 接受,但部分客户端/库可能不接受。 > 引自:[Configuring Pools](https://docs.ceph.com/en/tentacle/radosgw/pools/) / [Pool Placement and Storage Classes](https://docs.ceph.com/en/tentacle/radosgw/placement/) --- ## 五、前端与部署(HTTP Frontends) 来源:`frontends.rst` 全文。 ### 5.1 总览 Ceph 对象网关支持**两个嵌入式 HTTP 前端库**,通过 `rgw_frontends` 配置(语法见 `Config Reference`)。 | 前端 | 状态 | 引入版本 | 实现 | |---|---|---|---| | **beast** | **当前默认** | Mimic(`versionadded:: Mimic`) | 用 **Boost.Beast** 做 HTTP 解析,用 **Boost.Asio** 做异步网络 I/O | | **civetweb** | 旧版、现已非默认 | 文档未明确(源文只说是 "older and now non-default") | 每连接一个线程的线程模型,因此在接受连接时**自动**受 `rgw_thread_pool_size` 节流 | **线程模型与 QoS 的关键差异**(`config-ref.rst` 的 QoS 章节): > 较新的、也是默认的 `beast` 前端在接受新连接时**不受**线程池大小限制,因此在 Nautilus 版本引入了一个 scheduler 抽象以支持额外的请求调度方式。当前 scheduler 默认是一个 throttler,把活跃连接数限制在一个配置上限。基于 mClock 的 QoS 限流目前处于**实验(experimental)**阶段,**不建议用于生产**。当前 *dmclock_client* op queue 的实现把 RGW op 分为 admin、auth(swift auth、sts)、metadata、data 四类请求。 ### 5.2 `rgw_frontends` 主配置项 | 配置项 | 类型 | 默认值(默认值取自 src/common/options/rgw.yaml.in @ v20.2.4) | 含义 | |---|---|---|---| | `rgw_frontends` | str | `beast port=7480` | RGW frontends configuration | | `rgw_nfs_frontends` | str | `rgw-nfs` | 以 librgw/nfs 方式运行时的前端配置。逗号分隔的前端配置列表,每个配置由前端类型 + 可选的空格分隔 `key=value` 参数集组成。默认只启动 `rgw-nfs` 前端;其它前端(如 `beast`)通过此项启用,语法与 `rgw_frontends` 相同 | ### 5.3 Beast 前端选项(逐项) | 选项 | 描述 | 类型 | 默认值 | |---|---|---|---| | `port` / `ssl_port` | 设置 IPv4 与 IPv6 监听端口号。可多次指定,如 `port=80 port=8000` | Integer | `80` | | `endpoint` / `ssl_endpoint` | 以 `address[:port]` 形式设置监听地址。地址可以是点分十进制 IPv4,或用方括号包围的十六进制 IPv6。**指定 IPv6 endpoint 将只监听 v6**。可选端口对 `endpoint` 默认 80,对 `ssl_endpoint` 默认 443。可多次指定,如 `endpoint=[::1] endpoint=192.168.0.100:8000` | Integer | None | | `ssl_certificate` | SSL endpoint 使用的证书文件路径。若路径以 `config://` 为前缀,证书会从 ceph monitor 的 `config-key` 数据库中拉取 | String | None | | `ssl_private_key` | SSL endpoint 使用的私钥文件路径,可选。若未给出,则使用 `ssl_certificate` 文件作为私钥。同样支持 `config://` 前缀 | String | None | | `ssl_options` | 可选的冒号分隔 SSL context 选项列表(取值见下表) | String | `no_sslv2:no_sslv3:no_tlsv1:no_tlsv1_1` | | `ssl_ciphers` / `ssl_ciphersuites` | 可选的、冒号分隔的一个或多个 cipher 字符串,格式见 OpenSSL 的 `ciphers(1)` 手册。`ssl_ciphers` **只适用于 TLS v1.2 及以下**;`ssl_ciphersuites` **只适用于 TLS v1.3** | String | None | | `tcp_nodelay` | 置位则在连接上禁用 Nagle 算法(包尽快发出,而不等缓冲区满或超时)。`1`=对所有 socket 禁用 Nagle;`0`=保持默认(Nagle 启用) | Integer (0 or 1) | `0` | | `max_connection_backlog` | 可选的、等待 accept 的连接队列最大长度。未配置则使用 `boost::asio::socket_base::max_connections` 的值 | Integer | None | | `request_timeout_ms` | Beast 等待更多入站数据或出站数据的毫秒数,超时即放弃。**设为 0 表示禁用超时** | Integer | `65000` | | `max_header_size` | 单个请求可用的最大 header 字节数 | Integer | `16384`(Maximum: `65536`) | | `so_reuseport` | 置位则允许同一主机上的多个 RGW 实例监听同一 TCP 端口。`1`=允许;`0`=不允许 | Integer (0 or 1) | `0` | **`ssl_options` 可选值**: | 值 | 含义 | |---|---| | `default_workarounds` | Implement various bug workarounds | | `no_compression` | Disable compression | | `no_sslv2` | Disable SSL v2 | | `no_sslv3` | Disable SSL v3 | | `no_tlsv1` | Disable TLS v1 | | `no_tlsv1_1` | Disable TLS v1.1 | | `no_tlsv1_2` | Disable TLS v1.2 | | `single_dh_use` | Always create a new key when using tmp_dh parameters | ### 5.4 通用选项(所有前端都支持) | 选项 | 描述 | 类型 | 默认值 | |---|---|---|---| | `prefix` | 插入到所有请求 URI 中的前缀字符串。例如一个 swift-only 前端可以提供 `/swift` 的 URI 前缀 | String | None | ### 5.5 前端相关的性能/调优参数 | 配置项 | 类型 | 默认值(默认值取自 src/common/options/rgw.yaml.in @ v20.2.4) | 含义 / 与前端的关系 | |---|---|---|---| | `rgw_thread_pool_size` | int | `512` | RGW 请求处理线程池大小。官方 `long_desc`:**该参数决定在使用 civetweb 或 fastcgi 前端时 RGW 能处理的并发请求数**。数值越大可处理越多并发请求,代价是资源占用更高 | | `rgw_max_concurrent_requests` | int | `1024` | 最大并发 HTTP 请求数(beast 前端的 throttler 上限) | | `rgw_scheduler_type` | str | `throttler` | dmclock scheduler 类型,默认 throttler;另一个合法值 `dmclock` 是实验性的 | | `rgw_exit_timeout_secs` | int | `2_min` | RGW 关闭超时 | | `rgw_init_timeout` | int | `5_min` | 初始化超时 | | `rgw_num_control_oids` | int | `8` | 用于跨 RGW 通信的控制对象数量 | | `rgw_op_thread_timeout` | int | `10_min` | 异步 rados 协程操作的超时 | | `rgw_op_thread_suicide_timeout` | int | `0` | Ceph 对象网关进程死亡前的 timeout 秒数;设为 `0` 表示禁用 | | `rgw_print_continue` | bool | `true` | RGW 是否支持 100-continue | | `rgw_content_length_compat` | bool | `false` | 多个 content length header 的兼容性 | ### 5.6 配置示例 **最小 beast 前端(默认)**: ```ini [client.rgw.node1] rgw_frontends = beast port=7480 ``` **同时监听 80 与 8000、并开启 IPv6 端点**: ```ini [client.rgw.node1] rgw_frontends = beast port=80 port=8000 endpoint=[::1] endpoint=192.168.0.100:8000 ``` **启用 SSL(证书走 monitor config-key)**: ```ini [client.rgw.node1] rgw_frontends = beast ssl_endpoint=0.0.0.0:443 ssl_certificate=config://rgw/cert.pem ssl_private_key=config://rgw/key.pem ``` **为 swift-only 前端加 URI 前缀 + 关闭 Nagle + 允许多实例同端口**: ```ini [client.rgw.node1] rgw_frontends = beast port=7480 prefix=/swift tcp_nodelay=1 so_reuseport=1 ``` **注意**:配置写在 `[client.radosgw.{instance-name}]` 段时,对**未指定 instance-name** 的 `rgw`/`radosgw-admin` 命令不生效。要对所有 RGW 实例或所有 `radosgw-admin` 选项生效,应放到 `[global]` 或 `[client]` 段(`config-ref.rst` 原文要点)。 > 引自:[HTTP Frontends](https://docs.ceph.com/en/tentacle/radosgw/frontends/) --- ## 六、管理(Admin Guide) 来源:`admin.rst` 全文(30KB)+ `placement.rst` / `account.rst` / `layout.rst` / `troubleshooting.rst` / `config-ref.rst` 中出现的子命令。 ### 6.1 用户与子用户模型 Ceph 对象存储的用户管理**仅指 Ceph 对象存储服务的用户**,不是 Ceph 对象网关作为 Ceph 存储集群用户(`client.rgw.*`)的概念。 | 类型 | 说明 | |---|---| | **User** | 指 **S3 接口**的用户 | | **Subuser** | 指 **Swift 接口**的用户。subuser 归属于某个 user | 层级关系(官方 ditaa 转文本): ```text +---------+ | Account | +----+----+ | | +---------+ +-----+ User | +----+----+ | | +-----------+ +-----+ Subuser | +-----------+ ``` 要点(源文原文): - users 与 subusers 都可被创建、修改、查看、暂停(suspend)和删除。 - 可以为 user 添加 display name 和 email 地址。 - key 与 secret 可以指定,也可以自动生成。 - **生成或指定 key 时记住:user ID 对应 S3 key 类型,subuser ID 对应 Swift key 类型。** - **Swift key 有 access level:`read`、`write`、`readwrite`、`full`。** ### 6.2 `radosgw-admin` 子命令总表 > 下表把本册范围内出现的**每一个** `radosgw-admin` 子命令逐项列出。 #### 6.2.1 用户 / 子用户管理 | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `user create` | 创建 S3 用户(同时生成 access_key/secret_key) | `--uid`、`--display-name`、`--email`、`--key-type`、`--access-key`、`--secret-key`、`--gen-access-key`、`--gen-secret`、`--generate-key`、`--max-buckets`、`--suspended`、`--tenant`、`--account-id`、`--account-root`、`--admin`、`--system` | `radosgw-admin user create --uid=johndoe --display-name="John Doe" --email=john@example.com` | | `user info` | 查看用户信息(含 quota 设置) | `--uid` | `radosgw-admin user info --uid=johndoe` | | `user modify` | 修改用户属性(display name、email、placement、storage class、tags、account 归属、admin 标志) | `--uid`、`--display-name`、`--email`、`--placement-id`、`--storage-class`、`--tags`、`--account-id`、`--admin` / `--admin=0`、`--max-buckets`、`--suspended`、`--op-mask` | `radosgw-admin user modify --uid=johndoe --display-name="John E. Doe"` | | `user suspend` | 暂停用户(创建时默认启用) | `--uid` | `radosgw-admin user suspend --uid=johndoe` | | `user enable` | 重新启用被暂停的用户 | `--uid` | `radosgw-admin user enable --uid=johndoe` | | `user rm` | 删除用户及其所有 subuser | `--uid`、`--purge-data`、`--purge-keys` | `radosgw-admin user rm --uid=johndoe` | | `user stats` | 查看用户已消耗的配额用量 | `--uid`、`--sync-stats` | `radosgw-admin user stats --uid= --sync-stats` | | `subuser create` | 为某 user 创建 Swift 子用户 | `--uid`、`--subuser`、`--access=[read\|write\|readwrite\|full]`、`--key-type`、`--secret-key`、`--generate-secret` | `radosgw-admin subuser create --uid=johndoe --subuser=johndoe:swift --access=full` | | `subuser modify` | 修改子用户(主要是 access level) | `--uid`、`--subuser`、`--access`、`--secret`、`--key-type`、`--generate-secret` | `radosgw-admin subuser modify --uid=johndoe --subuser=johndoe:swift --access=full` | | `subuser rm` | 删除子用户(其所属 user 保留) | `--subuser`、`--purge-keys` | `radosgw-admin subuser rm --subuser=johndoe:swift` | 关于 `user rm` 的选项: | 选项 | 说明 | |---|---| | `--purge-data` | 清除与该 UID 关联的所有数据 | | `--purge-keys` | 清除与该 UID 关联的所有 key | 关于 `user suspend`:**禁用用户同时也禁用其所有 subuser**。 #### 6.2.2 密钥管理(`key`) Key 相关通用选项(源文原文): | 选项 | 说明 | |---|---| | `--key-type=` | 指定 key 类型,可选 `s3`、`swift` | | `--access-key=` | 手动指定 S3 access key | | `--secret-key=` | 手动指定 S3 secret key 或 Swift secret key | | `--gen-access-key` | 自动生成随机 S3 access key | | `--gen-secret` | 自动生成随机 S3 secret key 或随机 Swift secret key | | `--generate-key` | 创建用户时是否带凭据。**若为 false,则用户不能设置 `gen-secret`/`gen-access-key`/`access-key`/`secret-key`** | | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `key create`(S3) | 为 user 添加指定 S3 key 对 | `--uid`、`--key-type=s3`、`--access-key`、`--secret-key` | `radosgw-admin key create --uid=foo --key-type=s3 --access-key fooAccessKey --secret-key fooSecretKey` | | `key create`(Swift) | 为 subuser 附加指定 Swift secret key | `--subuser`、`--key-type=swift`、`--secret-key` | `radosgw-admin key create --subuser=foo:bar --key-type=swift --secret-key barSecret` | | `key create`(subuser + S3) | 把 subuser 与 S3 key 对关联,使 subuser 也能用 S3 API | `--subuser`、`--key-type=s3`、`--access-key`、`--secret-key` | `radosgw-admin key create --subuser=foo:bar --key-type=s3 --access-key barAccessKey --secret-key barSecretKey` | | `key rm`(S3) | 删除指定 S3 key 对 | `--uid`、`--key-type=s3`、`--access-key` | `radosgw-admin key rm --uid=foo --key-type=s3 --access-key=fooAccessKey` | | `key rm`(Swift) | 删除 Swift secret key | `--subuser`、`--key-type=swift` | `radosgw-admin key rm --subuser=foo:bar --key-type=swift` | 规则: - **一个 user 可以创建多对 S3 key。** - **一个 subuser 只能有一个 Swift secret key。** - 关于 `full` vs `readwrite`(官方 note):`full` **不等同于** `readwrite`。`full` 包含 `read` 与 `write`,**还包含访问控制策略(access control policy)**。 #### 6.2.3 管理能力(caps)与 admin/system 用户 | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `caps add` | 为用户添加管理能力 | `--uid`、`--caps` | `radosgw-admin caps add --uid=johndoe --caps="users=*;buckets=*"` | | `caps rm` | 移除用户的管理能力 | `--uid`、`--caps` | `radosgw-admin caps rm --uid=johndoe --caps="users=*"` | `--caps` 的取值语法(源文原文): ```text --caps="[users|buckets|metadata|usage|zone|amz-cache|info|bilog|mdlog|datalog|user-policy|oidc-provider|roles|ratelimit|user-info-without-keys|accounts]=[\*|read|write|read, write]" ``` 可对 **users、buckets、metadata、usage、zone、amz-cache、info、bilog、mdlog、datalog、user-policy、oidc-provider、roles、ratelimit、user-info-without-keys、accounts** 授予 `*`、`read`、`write` 或 `read, write`。 **Admin / System 用户**: | 标志 | 说明 | |---|---| | `--admin` | 拥有**全局读写权限**,适用于**所有 API(包括 S3 和 Swift)**,与 Admin Capabilities 不同,**且不能被 IAM policy 拒绝**。可用于排障恢复(例如用户误删了自己对 bucket/object 的权限时)。**警告**:不使用时考虑删除该用户或禁用其 access key,不要把 admin 权限给不可信用户 | | `--system` | 同样拥有全局读写权限。**仅应按 `Multisite Configuration` 文档所述使用** | ```bash # 创建 admin 用户 radosgw-admin user create --uid={username} --display-name="{display-name}" --admin # 给已有用户加 admin 标志 radosgw-admin user modify --uid={username} --admin # 移除 admin 标志 radosgw-admin user modify --uid={username} --admin=0 ``` #### 6.2.4 配额(quota) 配额可设在 **user** 及 user 拥有的 **bucket** 上(账号级见第八章)。 | 参数 | 说明 | |---|---| | `--max-objects` | 最大对象数。**负值禁用**该设置 | | `--max-size` | 配额大小,单位 B/K/M/G/T,**B 为默认**。负值禁用 | | `--quota-scope` | 配额作用域,可选 `bucket`、`user`(账号级为 `account`) | | `--bucket` | 指定 bucket 名(使 quota 作用于单个 bucket) | | `--uid` | 指定用户 | | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `quota set`(user 级) | 设置用户配额参数(**设置后必须 enable 才生效**) | `--quota-scope=user`、`--uid`、`--max-objects`、`--max-size` | `radosgw-admin quota set --quota-scope=user --uid=johndoe --max-objects=1024 --max-size=1024B` | | `quota enable`(user 级) | 启用已设置的用户配额 | `--quota-scope=user`、`--uid` | `radosgw-admin quota enable --quota-scope=user --uid=` | | `quota disable`(user 级) | 禁用已启用的用户配额 | `--quota-scope=user`、`--uid` | `radosgw-admin quota disable --quota-scope=user --uid=` | | `quota set`(bucket 级) | 设置 bucket 配额。指定 `--bucket` 则作用于单个 bucket;指定 `--uid` 则作用于该用户拥有的**所有** bucket | `--quota-scope=bucket`、`{--bucket\|--uid}`、`--max-objects`、`--max-size` | `radosgw-admin quota set --quota-scope=bucket --bucket=mybucket --max-size=10G` | | `quota enable`(bucket 级) | 启用 bucket 配额 | `--quota-scope=bucket`、`--uid` | `radosgw-admin quota enable --quota-scope=bucket --uid=` | | `quota disable`(bucket 级) | 禁用 bucket 配额 | `--quota-scope=bucket`、`--uid` | `radosgw-admin quota disable --quota-scope=bucket --uid=` | | `quota set`(account 级) | 设置账号配额 | `--quota-scope=account`、`--account-id`、`--max-size`、`--max-objects` | `radosgw-admin quota set --quota-scope=account --account-id={accountid} --max-size=10G` | | `quota enable`(account 级) | 启用账号配额 | `--quota-scope=account`、`--account-id` | `radosgw-admin quota enable --quota-scope=account --account-id={accountid}` | | `quota set`(account 下的 bucket 级) | 为账号设置 bucket 级配额 | `--quota-scope=bucket`、`--account-id`、`--max-objects` | `radosgw-admin quota set --quota-scope=bucket --account-id={accountid} --max-objects=1000000` | | `global quota get` | 读取 period 配置中的全局配额设置 | 无 | `radosgw-admin global quota get` | | `global quota set` | 写入全局配额设置 | `--quota-scope`、`--max-objects`、`--max-size` 等 | `radosgw-admin global quota set --quota-scope bucket --max-objects 1024` | | `global quota enable` | 启用全局配额 | `--quota-scope` | `radosgw-admin global quota enable --quota-scope bucket` | 要点: - **User Quotas are summed across all buckets owned by the user**(用户配额是该用户所有 bucket 的求和)。 - **设置配额参数后必须 enable 才生效**。 - **Update Quota Stats**:配额统计是异步更新的。可手动强制更新所有用户与所有 bucket 的配额统计:`radosgw-admin user stats --uid= --sync-stats`。 - **Default Quotas**:可以在 RGW 配置中设置默认配额。**这些默认值只在创建新用户时使用,对已有用户无影响。** 若设置了默认配额,则后续创建的所有用户都会设置该配额并**自动启用**。相关配置项:`rgw_bucket_default_quota_max_objects`、`rgw_bucket_default_quota_max_size`、`rgw_user_default_quota_max_objects`、`rgw_user_default_quota_max_size`、`rgw_account_default_quota_max_objects`、`rgw_account_default_quota_max_size`。 - **Global Quota 的生效方式(官方 note)**:在存在 realm 与 period 的多站点配置中,全局配额的改动必须用 `period update --commit` 提交;若没有 period,则必须重启 RGW 实例。 **Quota Cache(配额缓存)**: 配额统计被每个 RGW 实例缓存。若部署了多个 RGW 实例,该缓存可能导致配额无法被完美执行,因为每个实例可能持有不同的配额设置。 | 配置项 | 类型 | 默认值(默认值取自 src/common/options/rgw.yaml.in @ v20.2.4) | 含义 | |---|---|---|---| | `rgw_bucket_quota_ttl` | int | `10_min` | Bucket quota stats 缓存 TTL | | `rgw_user_quota_bucket_sync_interval` | int | `3_min` | User quota bucket 同步间隔 | | `rgw_user_quota_sync_interval` | int | `1_day` | User quota 同步间隔 | - **增大**这些值 → quota 操作更高效,但多 RGW 实例间配额设置不一致的可能性上升。 - **减小**这些值 → 多 RGW 实例间更接近完美的配额同步。 - **三个值都设为 `0`** → 配额缓存实际上被禁用,多实例将有完美的配额执行。 #### 6.2.5 速率限制(ratelimit) 「rate limit」包括:每分钟的**读操作数 / 写操作数**,以及每个用户或每个 bucket 每分钟可写/可读的**字节数**。 **读请求 vs 写请求**:REST 请求中使用 `GET` 或 `HEAD` 方法的操作是「读请求」,**所有其它请求**都是「写请求」。 **Metrics 如何工作(源文原文要点)**: - 每个对象网关**分别**跟踪 per-user 指标与 bucket 指标,**不与其它网关共享**。 - **配置的限制应除以活跃对象网关的数量。** 例:若要限制「user A」10 ops/分钟而集群有 2 个 RGW,则该限制应设为 `5`。 - 若请求在 RGW 之间**不均衡**,rate limit 可能利用不足。例:限制为 5 且有 2 个 RGW,但 LB 只把流量发给其中一个,则**有效限制就是 5 ops**(因为限制是按 RGW 强制的)。 - **bucket 限流到达但 user 限流未到达 → 请求被取消**;反之亦然。 - **带宽计量只在请求被接受之后发生**。这意味着即使 bucket 或 user 的 rate limit 在请求执行期间被达到,请求也会继续进行。 - RGW 会跟踪超出配置值的「**debt(欠账)**」;欠账的用户/bucket 会被阻止发送更多请求,直到欠账还清。**debt 的最大值是 max-read/write-bytes per minute 的两倍。** - 举例:若「user A」被限制为每分钟 1 字节读,而它尝试 `GET` 一个 1 GB 的对象,则该 `GET` 会失败。完成这个 1 GB 操作后,RGW 会阻止该用户的请求**最多两分钟**;两分钟后可再次发送 `GET`。 | 参数 | 说明 | |---|---| | `--bucket` | 为某个 bucket 指定 rate limit | | `--uid` | 为某个 user 指定 rate limit | | `--max-read-ops` | 限制每个 RGW 实例每分钟的读操作次数。`0` 禁用节流 | | `--max-read-bytes` | 限制每个 RGW 实例每分钟的读字节数。`0` 禁用节流 | | `--max-write-ops` | 限制每个 RGW 实例每分钟的写操作次数。`0` 禁用节流 | | `--max-write-bytes` | 限制每个 RGW 实例每分钟的写字节数。`0` 禁用节流 | | `--ratelimit-scope` | 限流作用域,可选 `bucket`、`user`、`anonymous`。**`anonymous` 仅对 global rate limit 可用** | | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `ratelimit set`(user) | 设置 user 限流参数 | `--ratelimit-scope=user`、`--uid`、`--max-read-ops`、`--max-read-bytes`、`--max-write-ops`、`--max-write-bytes` | `radosgw-admin ratelimit set --ratelimit-scope=user --uid=johndoe --max-read-ops=1024 --max-write-bytes=10240` | | `ratelimit get`(user) | 返回当前已配置的 user 限流参数 | `--ratelimit-scope=user`、`--uid` | `radosgw-admin ratelimit get --ratelimit-scope=user --uid=johndoe` | | `ratelimit enable`(user) | 启用已设置的 user 限流 | `--ratelimit-scope=user`、`--uid` | `radosgw-admin ratelimit enable --ratelimit-scope=user --uid=` | | `ratelimit disable`(user) | 禁用 user 限流 | `--ratelimit-scope=user`、`--uid` | `radosgw-admin ratelimit disable --ratelimit-scope=user --uid=johndoe` | | `ratelimit set`(bucket) | 设置 bucket 限流参数 | `--ratelimit-scope=bucket`、`--bucket`、`--max-read-ops`、`--max-read-bytes`、`--max-write-ops`、`--max-write-bytes` | `radosgw-admin ratelimit set --ratelimit-scope=bucket --bucket=mybucket --max-read-ops=1024 --max-write-bytes=10240` | | `ratelimit get`(bucket) | 返回 bucket 限流参数 | `--ratelimit-scope=bucket`、`--bucket` | `radosgw-admin ratelimit get --ratelimit-scope=bucket --bucket=mybucket` | | `ratelimit enable`(bucket) | 启用 bucket 限流 | `--ratelimit-scope=bucket`、`--bucket` | `radosgw-admin ratelimit enable --ratelimit-scope=bucket --bucket=` | | `ratelimit disable`(bucket) | 禁用 bucket 限流 | `--ratelimit-scope=bucket`、`--uid` | `radosgw-admin ratelimit disable --ratelimit-scope=bucket --uid=mybucket` | | `global ratelimit get` | 读取 period 配置中的全局限流设置 | 无 | `radosgw-admin global ratelimit get` | | `global ratelimit set` | 设置全局限流(bucket / user / anonymous 三种 scope) | `--ratelimit-scope`、`--max-read-ops`、`--max-read-bytes`、`--max-write-ops`、`--max-write-bytes` | `radosgw-admin global ratelimit set --ratelimit-scope bucket --max-read-ops=1024` | | `global ratelimit enable` | 启用全局限流 | `--ratelimit-scope` | `radosgw-admin global ratelimit enable --ratelimit-scope bucket` | **全局限流的三种用法**: ```bash # 1) 为所有 bucket 配置全局限流 radosgw-admin global ratelimit set --ratelimit-scope bucket --max-read-ops=1024 radosgw-admin global ratelimit enable --ratelimit-scope bucket # 2) 为所有已认证用户配置全局限流 radosgw-admin global ratelimit set --ratelimit-scope user --max-read-ops=1024 radosgw-admin global ratelimit enable --ratelimit-scope user # 3) 为所有未认证(匿名)用户配置全局限流 radosgw-admin global ratelimit set --ratelimit-scope=anonymous --max-read-ops=1024 radosgw-admin global ratelimit enable --ratelimit-scope=anonymous ``` 要点:**per-user 与 per-bucket 的 ratelimit 配置会覆盖 global 配置。** 在存在 realm 与 period 的多站点配置中,全局限流的任何改动必须用 `period update --commit` 提交;若无 period,则必须重启 RGW。 #### 6.2.6 用量(usage) **前提**:需要启用 usage log。在 `ceph.conf` 的 `[client.rgw]` 段加入 `rgw_enable_usage_log = true` 并重启 `radosgw` 服务。 > 官方 note:在 Ceph 提供一个能处理所有选项设置方式的可链接宏之前,建议在 central config 或 `ceph.conf` 中设置 `rgw_enable_usage_log = true` 并重启所有 RGW。 | 选项 | 说明 | |---|---| | `--start-date` | 过滤起始日期与可选的起始时间(**格式**:`yyyy-mm-dd [HH:MM:SS]`) | | `--end-date` | 过滤截止日期与可选的截止时间(**格式**:`yyyy-mm-dd [HH:MM:SS]`) | | `--show-log-entries` | 是否在统计中包含日志条目(`true` \| `false`) | | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `usage show` | 显示用量统计;省略 `--uid` 则显示所有用户的汇总 | `--uid`、`--start-date`、`--end-date`、`--show-log-entries` | `radosgw-admin usage show --uid=johndoe --start-date=2012-03-01 --end-date=2012-04-01` | | `usage trim` | 裁剪用量日志(可指定用户与日期范围) | `--uid`、`--start-date`、`--end-date` | `radosgw-admin usage trim --uid=johndoe --end-date=2013-12-31` | > **注意**:可以指定到分秒精度,但**指定的时间只以 1 小时分辨率存储**。 示例: ```bash radosgw-admin usage show --uid=johndoe --start-date=2012-03-01 --end-date=2012-04-01 radosgw-admin usage show --show-log-entries=false radosgw-admin usage trim --start-date=2010-01-01 --end-date=2010-12-31 radosgw-admin usage trim --uid=johndoe radosgw-admin usage trim --uid=johndoe --end-date=2013-12-31 ``` #### 6.2.7 其它本册出现的子命令 | 子命令 | 用途 | 关键参数 | 示例 | |---|---|---|---| | `zonegroup get` | 查看 zonegroup 配置(含 placement_targets、default_placement、api_name) | `--rgw-zonegroup` | `radosgw-admin zonegroup get` | | `zone get` | 查看 zone 配置(含 domain_root、placement_pools) | `--rgw-zone` | `radosgw-admin zone get --rgw-zone=default` | | `zone set` | 应用修改后的 zone 配置 | `--rgw-zone`、`--infile` | `radosgw-admin zone set --rgw-zone=default --infile=zone.json` | | `zonegroup placement add` | 向 zonegroup 添加 placement target 或 storage class | `--rgw-zonegroup`、`--placement-id`、`--storage-class` | `radosgw-admin zonegroup placement add --rgw-zonegroup default --placement-id temporary` | | `zone placement add` | 为 placement target / storage class 提供 zone 侧 pool 映射 | `--rgw-zone`、`--placement-id`、`--storage-class`、`--data-pool`、`--index-pool`、`--data-extra-pool`、`--compression`、`--placement-inline-data` | `radosgw-admin zone placement add --rgw-zone default --placement-id temporary --data-pool default.rgw.temporary.data --index-pool default.rgw.temporary.index --data-extra-pool default.rgw.temporary.non-ec` | | `zone placement modify` | 修改 placement(支持 `--placement-inline-data`) | 同上 | 文档未给出独立示例 | | `zonegroup placement default` | 修改 zonegroup 的默认 placement target | `--rgw-zonegroup`、`--placement-id` | `radosgw-admin zonegroup placement default --rgw-zonegroup default --placement-id new-placement` | | `bucket stats` | 查看 bucket 统计,会显示其 `placement_rule` | `--bucket` | `radosgw-admin bucket stats` | | `period update` | 提交 period 变更(多站点/全局配额/全局限流) | `--commit` | `radosgw-admin period update --commit` | | `gc list` | 查看等待垃圾回收的对象队列 | `--include-all` | `radosgw-admin gc list` | | `metadata list` | 列出元数据类型或某类型的条目 | 可选类型名(如 `bucket`、`bucket.instance`、`user`) | `radosgw-admin metadata list user` | | `metadata get` | 获取(或 set)元数据条目 | `bucket:`、`bucket.instance::`、`user:` | `radosgw-admin metadata get user:johndoe` | | `topic rm` | 删除通知 topic(账号迁移后清理旧 topic) | `--topic` | `radosgw-admin topic rm --topic topic1` | | `account create` | 创建账号 | `--account-name`、`--account-id`、`--email` | `radosgw-admin account create --account-name=acct1 --email=a@b.com` | | `account rm` | 删除账号 | `--account-id` | `radosgw-admin account rm --account-id={accountid}` | | `account stats` | 查看账号统计 | `--account-id`、`--sync-stats` | `radosgw-admin account stats --account-id={accountid} --sync-stats` | ### 6.3 输出与常见坑 **JSON 转义字符问题(官方 important)**: > 检查 key 输出。有时 `radosgw-admin` 会生成 JSON 转义字符(`\`),而某些客户端不知道如何处理 JSON 转义字符。补救办法包括:删除 JSON 转义字符(`\`)、把字符串用引号包起来、重新生成 key 并确保其不含 JSON 转义字符、或者手动指定 key 与 secret。 **创建用户的输出结构示例**: ```json { "user_id": "johndoe", "display_name": "John Doe", "email": "john@example.com", "suspended": 0, "max_buckets": 1000, "subusers": [], "keys": [ { "user": "johndoe", "access_key": "11BS02LGFB6AL6H1ADMW", "secret_key": "vzCEkuryfn060dfee4fgQPqFrncKEIkh3ZcdOANY"}], "swift_keys": [], "caps": [], "op_mask": "read, write, delete", "default_placement": "", "placement_tags": [], "bucket_quota": { "enabled": false, "max_size_kb": -1, "max_objects": -1}, "user_quota": { "enabled": false, "max_size_kb": -1, "max_objects": -1}, "temp_url_keys": []} ``` **创建 subuser 后的输出结构示例**: ```json { "user_id": "johndoe", "display_name": "John Doe", "email": "john@example.com", "suspended": 0, "max_buckets": 1000, "subusers": [ { "id": "johndoe:swift", "permissions": "full-control"}], "keys": [ { "user": "johndoe", "access_key": "11BS02LGFB6AL6H1ADMW", "secret_key": "vzCEkuryfn060dfee4fgQPqFrncKEIkh3ZcdOANY"}], "swift_keys": [], "caps": [], "op_mask": "read, write, delete", "default_placement": "", "placement_tags": [], "bucket_quota": { "enabled": false, "max_size_kb": -1, "max_objects": -1}, "user_quota": { "enabled": false, "max_size_kb": -1, "max_objects": -1}, "temp_url_keys": []} ``` **添加 S3 key 的输出示例**: ```json { "user_id": "foo", "rados_uid": 0, "display_name": "foo", "email": "foo@example.com", "suspended": 0, "keys": [ { "user": "foo", "access_key": "fooAccessKey", "secret_key": "fooSecretKey"}], } ``` **添加 Swift secret key 的输出示例**: ```json { "user_id": "foo", "rados_uid": 0, "display_name": "foo", "email": "foo@example.com", "suspended": 0, "subusers": [ { "id": "foo:bar", "permissions": "full-control"}], "swift_keys": [ { "user": "foo:bar", "secret_key": "asfghjghghmgm"}]} ``` **subuser 关联 S3 key 对的输出示例**: ```json { "user_id": "foo", "rados_uid": 0, "display_name": "foo", "email": "foo@example.com", "suspended": 0, "subusers": [ { "id": "foo:bar", "permissions": "full-control"}], "keys": [ { "user": "foo:bar", "access_key": "barAccessKey", "secret_key": "barSecretKey"}], } ``` > 引自:[Admin Guide](https://docs.ceph.com/en/tentacle/radosgw/admin/) --- ## 七、管理 API(Admin Ops API) 来源:`adminops.rst` 全文(55KB)。 ### 7.1 通用约定 | 约定 | 说明(源文原文要点) | |---|---| | 入口 | admin API 请求的 URI 以可配置的 **'admin' resource entry point** 开头(配置项 `rgw_admin_entry`,默认 `admin`,见第十二章) | | 认证 | **Authorization for the admin API duplicates the S3 authorization mechanism**(复用 S3 的认证机制) | | 授权 | 部分操作要求用户持有**特殊的管理能力(administrative capabilities)** | | 响应格式 | 实体类型(XML 或 JSON)可用请求中的 **`format`** 选项指定;**未指定时默认为 JSON** | | 请求/响应符号 | 下文语法中的 `{admin}` = admin 入口点;`{fqdn}` = 网关的完全限定域名 | ### 7.2 操作总览表 | # | 操作 | HTTP 方法 | 路径 | 所需 caps | |---|---|---|---|---| | 1 | Get Usage | `GET` | `/{admin}/usage` | `usage=read` | | 2 | Trim Usage | `DELETE` | `/{admin}/usage` | `usage=write` | | 3 | Get User Info | `GET` | `/{admin}/user` | `users=read` 或 `user-info-without-keys=read` | | 4 | Create Account | `POST` | `/{admin}/account` | `accounts=write` | | 5 | Modify Account | `PUT` | `/{admin}/account` | `accounts=write` | | 6 | Get Account Info | `GET` | `/{admin}/account` | `accounts=write` | | 7 | Remove Account | `DELETE` | `/{admin}/account` | `accounts=write` | | 8 | Create User | `PUT` | `/{admin}/user` | `users=write` | | 9 | Modify User | `POST` | `/{admin}/user` | `users=write` | | 10 | Remove User | `DELETE` | `/{admin}/user` | `users=write` | | 11 | Create Subuser | `PUT` | `/{admin}/user?subuser` | `users=write` | | 12 | Modify Subuser | `POST` | `/{admin}/user?subuser` | `users=write` | | 13 | Remove Subuser | `DELETE` | `/{admin}/user?subuser` | `users=write` | | 14 | Create Key | `PUT` | `/{admin}/user?key` | `users=write` | | 15 | Remove Key | `DELETE` | `/{admin}/user?key` | `users=write` | | 16 | Get Bucket Info | `GET` | `/{admin}/bucket` | `buckets=read` | | 17 | Check Bucket Index | `GET` | `/{admin}/bucket?index` | `buckets=write` | | 18 | Remove Bucket | `DELETE` | `/{admin}/bucket` | `buckets=write` | | 19 | Unlink Bucket | `POST` | `/{admin}/bucket` | `buckets=write` | | 20 | Link Bucket | `PUT` | `/{admin}/bucket` | `buckets=write` | | 21 | Remove Object | `DELETE` | `/{admin}/bucket?object` | `buckets=write` | | 22 | Get Bucket or Object Policy | `GET` | `/{admin}/bucket?policy` | `buckets=read` | | 23 | Add A User Capability | `PUT` | `/{admin}/user?caps` | `users=write` | | 24 | Remove A User Capability | `DELETE` | `/{admin}/user?caps` | `users=write` | | 25 | Get/Set User Quota | `GET` / `PUT` | `/{admin}/user?quota"a-type=user` | `users=read` / `users=write` | | 26 | Get/Set Bucket Quota(user 下) | `GET` / `PUT` | `/{admin}/user?quota"a-type=bucket` | `users=read` / `users=write` | | 27 | Set Quota for an Individual Bucket | `PUT` | `/{admin}/bucket?quota` | `buckets=write` | | 28 | Set Account Quota | `PUT` | `/{admin}/account?quota"a-type=account` | `accounts=write` | | 29 | Set Bucket Quota under an Account | `PUT` | `/{admin}/account?quota"a-type=bucket` | `accounts=write` | | 30 | Get User Rate Limit | `GET` | `/{admin}/ratelimit?ratelimit-scope=user` | `ratelimit=read` | | 31 | Set User Rate Limit | `POST` | `/{admin}/ratelimit?ratelimit-scope=user` | `ratelimit=write` | | 32 | Get Bucket Rate Limit | `GET` | `/{admin}/ratelimit?ratelimit-scope=bucket` | `users=read`(源文如此) | | 33 | Set Rate Limit for an Individual Bucket | `POST` | `/{admin}/ratelimit?ratelimit-scope=bucket` | `ratelimit=write` | | 34 | Get Global Rate Limit | `GET` | `/{admin}/ratelimit?global` | `ratelimit=read` | | 35 | Set Global User Rate Limit | `POST` | `/{admin}/ratelimit?ratelimit-scope=user&global` | `ratelimit=write` | | 36 | Set Global Rate Limit Bucket | `POST` | `/{admin}/ratelimit?ratelimit-scope=bucket&global` | `ratelimit=write` | | 37 | Set Global Anonymous User Rate Limit | `POST` | `/{admin}/ratelimit?ratelimit-scope=anon&global` | `ratelimit=write` | | 38 | Get RGW cluster/endpoint Info | `GET` | `/{admin}/info` | `info=read` | ### 7.3 Info **Get RGW cluster/endpoint information.** `:caps: info=read` ```http GET /{admin}/info?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**:None. **Response Entities**(成功时含 `info` section): | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `info` | 所有返回信息的容器 | Container | — | | `cluster_id` | RGW 集群的后端存储控制标识符(典型情况下即 `librados::rados::cluster_fsid()` 的返回值),通常唯一 | String | `info` | **Special Error Responses**:None. ### 7.4 Get Usage **Request bandwidth usage information.** `:caps: usage=read` > 注意:**该特性默认禁用**,可在 `ceph.conf` 适当段中设置 `rgw enable usage log = true` 启用;`ceph.conf` 的修改需要重启 radosgw 进程生效。 ```http GET /{admin}/usage?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 请求信息的用户。未指定则应用于所有用户 | String | `foo_user` | No | | `start` | 指定所请求数据起始时间的日期与(可选)时间 | String | `2012-09-25 16:00:00` | No | | `end` | 指定所请求数据结束时间的日期与(可选)时间(**不含**) | String | `2012-09-25 16:00:00` | No | | `show-entries` | 是否返回数据条目 | Boolean | True [True] | No | | `show-summary` | 是否返回数据汇总 | Boolean | True [True] | No | **Response Entities**: | 实体 | 描述 | 类型 | |---|---|---| | `usage` | 用量信息的容器 | Container | | `entries` | 用量条目信息的容器 | Container | | `user` | 用户数据信息的容器 | Container | | `owner` | 拥有这些 bucket 的用户名 | String | | `bucket` | bucket 名 | String | | `time` | 数据的时间下界(**取整到相关第一个小时的起点**) | String | | `epoch` | 以自 1970-01-01 起的秒数表示的时间 | String | | `categories` | 统计类别的容器 | Container | | `entry` | 统计条目的容器 | Container | | `category` | 提供统计的请求类别名 | String | | `bytes_sent` | RADOS Gateway 发出的字节数 | Integer | | `bytes_received` | RADOS Gateway 收到的字节数 | Integer | | `ops` | 操作次数 | Integer | | `successful_ops` | 成功操作次数 | Integer | | `summary` | 统计汇总的容器 | Container | | `total` | 汇总聚合总计的容器 | Container | **Special Error Responses**:TBD. ### 7.5 Trim Usage **Remove usage information.** 未指定日期则移除**全部**用量信息。`:caps: usage=write` ```http DELETE /{admin}/usage?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 请求信息的用户。未指定则应用于所有用户 | String | `foo_user` | No | | `start` | 起始日期与(可选)时间 | String | `2012-09-25 16:00:00` | No | | `end` | 结束日期与(可选)时间(不含) | String | `2012-09-25 16:00:00` | No | | `remove-all` | **当未指定 uid 时必需**,用于确认多用户数据移除 | Boolean | True [False] | No | **Special Error Responses**:TBD. ### 7.6 Get User Info `:caps: users=read` 或 `user-info-without-keys=read` > 若 cap `user-info-without-keys` 设为 `read` 或 `*`,**响应中不会包含 S3 keys 与 Swift keys**,除非执行该操作的用户是 system user、admin user,或者 cap `users` 设为 `read`。 > > 必须以请求参数形式提供 `uid` 或 `access-key` 之一。**推荐使用 uid。** 若两者都提供但对应不同用户,则返回 `uid` 所指定用户的信息。 ```http GET /{admin}/user?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 请求信息的用户 | String | `foo_user` | Yes | | `access-key` | 请求信息用户的 S3 access key | String | `ABCD0EF12GHIJ2K34LMN` | No | **Response Entities**: | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `user` | 用户数据信息的容器 | Container | — | | `user_id` | 用户 id | String | `user` | | `display_name` | 用户的显示名 | String | `user` | | `suspended` | 用户是否被暂停 | Boolean | `user` | | `max_buckets` | 用户可拥有的最大 bucket 数 | Integer | `user` | | `subusers` | 与该用户账号关联的 subuser | Container | `user` | | `keys` | 与该用户账号关联的 S3 key | Container | `user` | | `swift_keys` | 与该用户账号关联的 Swift key | Container | `user` | | `caps` | 用户能力 | Container | `user` | **Special Error Responses**:None. ### 7.7 Create Account > versionadded:: Squid — `:caps: accounts=write` ```http POST /{admin}/account?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `id` | 待创建 account 的 ID | String | `RGW00000000000000001` | Yes | | `name` | 待创建 account 的名称 | String | `account_name` | Yes | | `email` | 与 account 关联的 email 地址 | String | `foo@bar.com` | No | | `tenant` | account 所属的 Tenant | string | `tenant1` | No | | `max-users` | account 可拥有的最大用户数,默认 1000 | Integer | 500 [1000] | No | | `max-roles` | account 可拥有的最大 role 数,默认 1000 | Integer | 500 [1000] | No | | `max-groups` | account 可拥有的最大 group 数,默认 1000 | Integer | 500 [1000] | No | | `max-access-keys` | account 可拥有的最大 access key 数,默认 4 | Integer | 1 [4] | No | | `max-buckets` | account 可拥有的最大 bucket 数,默认 1000 | Integer | 500 [1000] | No | > **Account ID 格式**:必须为 **20 个字符**,格式为字符串 `RGW` 后跟 **17 个数字字符**。 **Response Entities**: | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `account` | account 信息的容器 | Container | — | | `id` | 创建的 account ID | String | `account` | | `tenant` | account 所属的 Tenant | String | `account` | | `name` | 创建的 account 名称 | String | `account` | | `email` | 关联的 email 地址 | String | `account` | | `max_users` | 可拥有的最大用户数 | Integer | `account` | | `max_roles` | 可拥有的最大 role 数 | Integer | `account` | | `max_groups` | 可拥有的最大 group 数 | Integer | `account` | | `max_buckets` | 可拥有的最大 bucket 数 | Integer | `account` | | `max_access_keys` | 可拥有的最大 access key 数 | Integer | `account` | | `quota` | account 级配额信息容器 | Container | `account` | | `enabled` | account 级配额是否启用 | Bool | `quota` | | `check_on_raw` | 配额是否基于 raw usage 而非 4 KiB 向上取整后的用量检查 | Bool | `quota` | | `max_size` | 最大配额大小(字节) | Integer | `quota` | | `max_size_kb` | 最大配额大小(KB) | Integer | `quota` | | `max_objects` | account 可拥有的最大对象数 | Integer | `quota` | | `bucket_quota` | account 的 bucket 级配额信息容器 | Container | `account` | | `enabled` | account 的 bucket 级配额是否启用 | Bool | `bucket_quota` | | `check_on_raw` | bucket 配额是否基于 raw usage 检查 | Bool | `bucket_quota` | | `max_size` | account 下 bucket 的最大配额字节数 | Integer | `bucket_quota` | | `max_size_kb` | account 下 bucket 的最大配额 KB 数 | Integer | `bucket_quota` | | `max_objects` | account 下单个 bucket 可拥有的最大对象数 | Integer | `bucket_quota` | **Special Error Responses**: | 错误 | 描述 | Code | |---|---|---| | `AccountAlreadyExists` | 尝试创建已存在的 account(account ID 或 email 已被占用时会发生) | 409 Conflict | ### 7.8 Modify Account > versionadded:: Squid — `:caps: accounts=write`。**必须提供 `id`、`name` 或 `email` 之一。** ```http PUT /{admin}/account?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `id` | 待修改 account 的 ID | String | `RGW00000000000000001` | No | | `name` | 待修改 account 的名称 | String | `account_name` | No | | `email` | 待修改 account 的 email | String | `foo@bar.com` | No | | `max-users` | 最大用户数,默认 1000 | Integer | 500 [1000] | No | | `max-roles` | 最大 role 数,默认 1000 | Integer | 500 [1000] | No | | `max-groups` | 最大 group 数,默认 1000 | Integer | 500 [1000] | No | | `max-access-keys` | 最大 access key 数,默认 4 | Integer | 1 [4] | No | | `max-buckets` | 最大 bucket 数,默认 1000 | Integer | 500 [1000] | No | **Response Entities**:与 7.7 Create Account 的响应实体**完全相同**(`account` 容器 + `id`/`tenant`/`name`/`email`/`max_users`/`max_roles`/`max_groups`/`max_buckets`/`max_access_keys`/`quota`/`bucket_quota` 及其子字段)。 **Special Error Responses**:None. ### 7.9 Get Account Info > versionadded:: Squid — `:caps: accounts=write`。**必须提供 `id` 或 `name` 之一。** ```http GET /{admin}/account?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `id` | 要获取信息的 account ID | String | `RGW00000000000000001` | No | | `name` | 要获取信息的 account 名称 | String | `account_name` | No | **Response Entities**:与 7.7 相同(`account` 及其全部子字段)。 **Special Error Responses**:None. ### 7.10 Remove Account > versionadded:: Squid — `:caps: accounts=write`。**必须提供 `id`、`name` 或 `email` 之一。** ```http DELETE /{admin}/account?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `id` | 待移除 account 的 ID | String | `RGW00000000000000001` | No | | `tenant` | account 所属的 Tenant | String | `tenant` | No | | `name` | 待移除 account 的名称 | String | `account_name` | No | | `email` | 待移除 account 的 email | String | `foo@bar.com` | No | **Response Entities**:None. **Special Error Responses**:None. ### 7.11 Create User `:caps: users=write` > 默认会自动创建一对 S3 key 并在响应中返回。若只提供 `access-key` 或 `secret-key` 之一,则省略的那个会自动生成。默认情况下,生成的 key 会被**加入 keyring 而不替换**已有 key 对。若指定了 `access-key` 且其指向该用户已拥有的某个 key,则该 key 会被**修改**。 ```http PUT /{admin}/user?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 待创建的用户 ID | String | `foo_user` | Yes | | `display-name` | 待创建用户的显示名 | String | `foo user` | Yes | | `email` | 与用户关联的 email 地址 | String | `foo@bar.com` | No | | `key-type` | 要生成的 key 类型,选项 `swift`、`s3`(默认) | String | `s3` [`s3`] | No | | `access-key` | 指定 access key | String | `ABCD0EF12GHIJ2K34LMN` | No | | `secret-key` | 指定 secret key | String | `0AbCDEFg1h2i34JklM5nop6QrSTUV+WxyzaBC7D8` | No | | `user-caps` | 用户能力 | String | `usage=read, write; users=read` | No | | `generate-key` | 生成新 key 对并加入已有 keyring | Boolean | True [True] | No | | `max-buckets` | 指定用户可拥有的最大 bucket 数 | Integer | 500 [1000] | No | | `suspended` | 指定用户是否被暂停 | Boolean | False [False] | No | | `tenant` | (versionadded:: Jewel)用户所属的 Tenant | string | `tenant1` | No | | `default-placement` | 用户的默认 placement | string | `default-placement` | No | | `default-storage-class` | 用户的默认 storage class;**设置此项时必须同时定义 `default-placement`** | string | `STANDARD-1A` | No | | `account-id` | (versionadded:: Squid)用户所属的 account | string | `RGW00000000000000001` | No | > 自 Luminous 起,tenant 既可以作为 uid 的一部分(`tenant$user` 语法)指定,也可以作为额外的请求参数指定。 **Response Entities**: | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `user` | 用户数据信息的容器 | Container | — | | `tenant` | 用户所属的 tenant | String | `user` | | `user_id` | 用户 id | String | `user` | | `display_name` | 显示名 | String | `user` | | `suspended` | 是否被暂停 | Boolean | `user` | | `max_buckets` | 可拥有的最大 bucket 数 | Integer | `user` | | `subusers` | 关联的 subuser | Container | `user` | | `keys` | 关联的 S3 key | Container | `user` | | `swift_keys` | 关联的 Swift key | Container | `user` | | `caps` | 用户能力 | Container | `user` | **Special Error Responses**: | 错误 | 描述 | Code | |---|---|---| | `UserExists` | 尝试创建已存在的用户 | 409 Conflict | | `InvalidAccessKey` | 指定了无效的 access key | 400 Bad Request | | `InvalidKeyType` | 指定了无效的 key 类型 | 400 Bad Request | | `InvalidSecretKey` | 指定了无效的 secret key | 400 Bad Request | | `KeyExists` | 提供的 access key 已存在且属于另一个用户 | 409 Conflict | | `EmailExists` | 提供的 email 地址已存在 | 409 Conflict | | `InvalidCapability` | 尝试授予无效的管理能力 | 400 Bad Request | ### 7.12 Modify User `:caps: users=write` ```http POST /{admin}/user?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 待修改的用户 ID | String | `foo_user` | Yes | | `display-name` | 待修改的显示名 | String | `foo user` | No | | `email` | 关联的 email 地址 | String | `foo@bar.com` | No | | `generate-key` | 生成新 key 对并加入已有 keyring | Boolean | True [False] | No | | `access-key` | 指定 access key | String | `ABCD0EF12GHIJ2K34LMN` | No | | `secret-key` | 指定 secret key | String | `0AbCDEFg1h2i34JklM5nop6QrSTUV+WxyzaBC7D8` | No | | `key-type` | key 类型,选项 `swift`、`s3`(默认) | String | `s3` | No | | `max-buckets` | 最大 bucket 数 | Integer | 500 [1000] | No | | `suspended` | 是否暂停 | Boolean | False [False] | No | | `op-mask` | 待修改的 op-mask | String | `read, write, delete, *` | No | | `default-placement` | 用户的默认 placement | string | `default-placement` | No | | `default-storage-class` | 用户的默认 storage class;设置此项时必须定义 `default-placement` | string | `STANDARD-1A` | No | **Response Entities**:`user` 容器 + `user_id`、`display_name`、`suspended`、`max_buckets`、`subusers`、`keys`、`swift_keys`、`caps`(Parent 均为 `user`)。 **Special Error Responses**:`InvalidAccessKey`(400)、`InvalidKeyType`(400)、`InvalidSecretKey`(400)、`KeyExists`(409)、`EmailExists`(409)、`InvalidCapability`(400)。 ### 7.13 Remove User `:caps: users=write` ```http DELETE /{admin}/user?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 待移除的用户 ID | String | `foo_user` | Yes | | `purge-data` | 指定时,属于该用户的 bucket 与对象也会被移除 | Boolean | True | No | **Response Entities**:None. **Special Error Responses**:None. ### 7.14 Create Subuser `:caps: users=write` > 创建一个新的 subuser(主要用于使用 Swift API 的客户端)。注意:**一般来说,要使 subuser 有用,必须通过 `access` 授予权限。** 与创建用户一样,如果指定了 `subuser` 而没有指定 `secret`,则会自动生成 secret key。 ```http PUT /{admin}/user?subuser&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 在其下创建 subuser 的用户 ID | String | `foo_user` | Yes | | `subuser` | 待创建的 subuser ID | String | `sub_foo` | Yes | | `secret-key` | 指定 secret key | String | `0AbCDEFg1h2i34JklM5nop6QrSTUV+WxyzaBC7D8` | No | | `key-type` | 要生成的 key 类型,选项 `swift`(默认)、`s3` | String | `swift` [`swift`] | No | | `access` | 设置 sub-user 的访问权限,应为 `read, write, readwrite, full` 之一 | String | `read` | No | | `generate-secret` | 生成 secret key | Boolean | True [False] | No | **Response Entities**: | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `subusers` | 与用户账号关联的 subuser | Container | — | | `id` | subuser id | String | `subusers` | | `permissions` | subuser 对用户账号的访问权限 | String | `subusers` | **Special Error Responses**:`SubuserExists`(409)、`InvalidKeyType`(400)、`InvalidSecretKey`(400)、`InvalidAccess`(400)。 ### 7.15 Modify Subuser `:caps: users=write` ```http POST /{admin}/user?subuser&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 其下 subuser 待修改的用户 ID | String | `foo_user` | Yes | | `subuser` | 待修改的 subuser ID | String | `sub_foo` | Yes | | `generate-secret` | 为 subuser 生成新 secret key,**替换**已有 key | Boolean | True [False] | No | | `secret` | 指定 secret key | String | `0AbCDEFg1h2i34JklM5nop6QrSTUV+WxyzaBC7D8` | No | | `key-type` | key 类型,选项 `swift`(默认)、`s3` | String | `swift` [`swift`] | No | | `access` | 访问权限,应为 `read, write, readwrite, full` 之一 | String | `read` | No | **Response Entities**:同 7.14(`subusers` → `id`、`permissions`)。 **Special Error Responses**:`InvalidKeyType`(400)、`InvalidSecretKey`(400)、`InvalidAccess`(400)。 ### 7.16 Remove Subuser `:caps: users=write` ```http DELETE /{admin}/user?subuser&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 其下 subuser 待移除的用户 ID | String | `foo_user` | Yes | | `subuser` | 待移除的 subuser ID | String | `sub_foo` | Yes | | `purge-keys` | 移除属于该 subuser 的 key | Boolean | True [True] | No | **Response Entities**:None. **Special Error Responses**:None. ### 7.17 Create Key `:caps: users=write` > 创建新 key。若指定了 `subuser`,则默认创建的 key 为 swift 类型。若只提供 `access-key` 或 `secret-key` 之一,则省略的那个会自动生成。默认情况下,生成的 key 被加入 keyring 而不替换已有 key 对。若指定了 `access-key` 且指向该用户已拥有的 key,则该 key 会被修改。**响应是一个容器,列出与所创建 key 同类型的所有 key。** 注意:**创建 swift key 时指定 `access-key` 选项无效**。此外,**每个 user 或 subuser 只能持有一个 swift key**。 ```http PUT /{admin}/user?key&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 接收新 key 的用户 ID | String | `foo_user` | Yes | | `subuser` | 接收新 key 的 subuser ID | String | `sub_foo` | No | | `key-type` | 要生成的 key 类型,选项 `swift`、`s3`(默认) | String | `s3` [`s3`] | No | | `access-key` | 指定 access key | String | `AB01C2D3EF45G6H7IJ8K` | No | | `secret-key` | 指定 secret key | String | `0ab/CdeFGhij1klmnopqRSTUv1WxyZabcDEFgHij` | No | | `generate-key` | 生成新 key 对并加入已有 keyring | Boolean | True [True] | No | | `active` | 激活或停用某个 key | Boolean | True [True] | No | **Response Entities**: | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `keys` | 与该用户账号关联的、所创建类型的 key | Container | — | | `user` | 与 key 关联的用户账号 | String | `keys` | | `access-key` | access key | String | `keys` | | `secret-key` | secret key | String | `keys` | **Special Error Responses**:`InvalidAccessKey`(400)、`InvalidKeyType`(400)、`InvalidSecretKey`(400)、`KeyExists`(409)。 ### 7.18 Remove Key `:caps: users=write` ```http DELETE /{admin}/user?key&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `access-key` | 待移除的 S3 key 对的 access key | String | `AB01C2D3EF45G6H7IJ8K` | Yes | | `uid` | 要从其移除 key 的用户 | String | `foo_user` | No | | `subuser` | 要从其移除 key 的 subuser | String | `sub_foo` | No | | `key-type` | 待移除的 key 类型,选项 `swift`、`s3`。**注意:移除 swift key 时必需** | String | `swift` | No | **Special Error Responses**:None. **Response Entities**:None. ### 7.19 Get Bucket Info `:caps: buckets=read` > 获取已有 bucket 子集的信息。若指定了 `uid` 而未指定 `bucket`,则返回该用户拥有的**所有** bucket。若只指定 `bucket`,则检索该特定 bucket 的信息。 > 若指定 `max-entries` 限制返回 bucket 数,**响应体结构会变化**,包含 `buckets`、`count` 和 `truncated` 三个 key;若 `truncated` 为 true 还会加入 `marker` key。 ```http GET /{admin}/bucket?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 要返回信息的 bucket | String | `foo_bucket` | No | | `uid` | 要检索 bucket 信息的用户 | String | `foo_user` | No | | `stats` | 返回 bucket 统计信息 | Boolean | True [False] | No | | `max-entries` | 要返回的 bucket 列表条目数 | Integer | 100 | No | | `marker` | 列举 bucket 时使用的 marker | String (bucket name) | `my-bucket` | No | **Response Entities**: | 实体 | 描述 | 类型 | Parent | |---|---|---|---| | `stats` | 每 bucket 信息 | Container | — | | `buckets` | 包含一个或多个 bucket 容器的列表 | Container | — | | `bucket` | 单个 bucket 信息的容器 | Container | `buckets` | | `name` | bucket 名 | String | `bucket` | | `pool` | bucket 存储所在的 pool | String | `bucket` | | `id` | 唯一的 bucket id | String | `bucket` | | `marker` | 内部 bucket tag | String | `bucket` | | `owner` | bucket owner 的用户 id | String | `bucket` | | `usage` | 存储用量信息 | Container | `bucket` | | `index` | bucket index 的状态 | String | `bucket` | | `count` | 返回的 bucket 数,仅在指定 `max-entries` 时出现 | Integer | — | | `truncated` | 仅在指定 `max-entries` 时,若响应被截断则为 true | Boolean | — | | `marker` | 若 `truncated` 为 true,返回用于继续分页的 marker(bucket 名) | String | — | **Special Error Responses**:`IndexRepairFailed`(Bucket index repair failed,409 Conflict)。 ### 7.20 Check Bucket Index `:caps: buckets=write` > 检查已有 bucket 的 index。**注意:要用 `check-objects` 检查 multipart 对象计数,必须把 `fix` 设为 True。** ```http GET /{admin}/bucket?index&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 要返回信息的 bucket | String | `foo_bucket` | Yes | | `check-objects` | 检查 multipart 对象计数 | Boolean | True [False] | No | | `fix` | 检查时同时修复 bucket index | Boolean | False [False] | No | **Response Entities**:`index`(Status of bucket index,String)。 **Special Error Responses**:`IndexRepairFailed`(409)。 ### 7.21 Remove Bucket `:caps: buckets=write` ```http DELETE /{admin}/bucket?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 待移除的 bucket | String | `foo_bucket` | Yes | | `tenant` | bucket 所属的 tenant | String | `tenant1` | No | | `purge-objects` | 删除前先移除 bucket 的对象 | Boolean | True [False] | No | | `bypass-gc` | 绕过垃圾回收 | Boolean | True [False] | No | **Response Entities**:None. **Special Error Responses**:`BucketNotEmpty`(尝试删除非空 bucket,409)、`ObjectRemovalFailed`(无法移除对象,409)。 ### 7.22 Unlink Bucket `:caps: buckets=write` — 把 bucket 从指定用户**解绑**(主要用于变更 bucket 归属)。 ```http POST /{admin}/bucket?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 待解绑的 bucket | String | `foo_bucket` | Yes | | `uid` | 要从其解绑 bucket 的用户 ID | String | `foo_user` | Yes | **Response Entities**:None. **Special Error Responses**:`BucketUnlinkFailed`(409)。 ### 7.23 Link Bucket `:caps: buckets=write` — 把 bucket 链接到指定用户,并**从任何之前的用户解绑**。 ```http PUT /{admin}/bucket?format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 待(重新)链接的 bucket 名 | String | `foo_bucket` | Yes | | `bucket-id` | 待(重新)链接的 bucket id | String | `dev.6607669.420` | No | | `uid` | 要链接到的用户 ID | String | `foo_user` | Yes | **Response Entities**:`bucket` 容器 → `name`、`pool`、`id`、`marker`、`owner`、`usage`、`index`(Parent 均为 `bucket`)。 **Special Error Responses**:`BucketUnlinkFailed`(409)、`BucketLinkFailed`(409)。 ### 7.24 Remove Object `:caps: buckets=write` — **注意:不要求 owner 处于非 suspended 状态。** ```http DELETE /{admin}/bucket?object&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 包含待移除对象的 bucket | String | `foo_bucket` | Yes | | `object` | 待移除的对象 | String | `foo.txt` | Yes | **Response Entities**:None. **Special Error Responses**:`NoSuchObject`(404)、`ObjectRemovalFailed`(409)。 ### 7.25 Get Bucket or Object Policy `:caps: buckets=read` ```http GET /{admin}/bucket?policy&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `bucket` | 要读取 policy 的 bucket | String | `foo_bucket` | Yes | | `object` | 要读取 policy 的对象 | String | `foo.txt` | No | **Response Entities**:`policy`(Access control policy,Container)。 **Special Error Responses**:`IncompleteBody`(bucket policy 请求未指定 bucket,或 object policy 请求未指定 bucket 与 object,400)。 ### 7.26 Add A User Capability `:caps: users=write` ```http PUT /{admin}/user?caps&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 要添加管理能力的用户 ID | String | `foo_user` | Yes | | `user-caps` | 要添加到该用户的管理能力 | String | `usage=read,write;user=write` | Yes | **Response Entities**:`user` 容器 → `user_id`、`caps`。 **Special Error Responses**:`InvalidCapability`(400)。 **Example Request**: ```http PUT /{admin}/user?caps&user-caps=usage=read,write;user=write&format=json HTTP/1.1 Host: {fqdn} Content-Type: text/plain Authorization: {your-authorization-token} ``` ### 7.27 Remove A User Capability `:caps: users=write` ```http DELETE /{admin}/user?caps&format=json HTTP/1.1 Host: {fqdn} ``` **Request Parameters**: | 参数 | 描述 | 类型 | 示例 | 必填 | |---|---|---|---|---| | `uid` | 要移除管理能力的用户 ID | String | `foo_user` | Yes | | `user-caps` | 要从该用户移除的管理能力 | String | `usage=read, write` | Yes | **Response Entities**:`user` 容器 → `user_id`、`caps`。 **Special Error Responses**:`InvalidCapability`(400)、`NoSuchCap`(用户不具备指定的能力,404)。 ### 7.28 Quotas(配额) Admin Operations API 允许在 **user**、user 拥有的 **bucket**、**account**、以及 account 拥有的 **bucket** 上设置配额。配额包括 bucket 中的最大对象数与最大存储大小(MB)。 **能力要求**: | 对象 | 查看 | 设置/修改/禁用 | |---|---|---| | user / user 的 bucket | `users=read` | `users=write` | | account / account 的 bucket | `accounts=read` | `accounts=write` | **合法参数**: | 参数 | 说明 | |---|---| | `bucket` | 为某用户拥有的 bucket 指定配额 | | `max-objects` | 最大对象数。**负值禁用**该设置 | | `max-size` | 最大字节数配额;`max-size-kb` 以 KiB 指定。**负值禁用** | | `quota-type` | 配额作用域。user 级配额可选 `bucket`、`user`;account 级配额可选 `bucket`、`account` | | `enabled` | 是否启用配额,值为 `'True'` 或 `'False'` | **各操作**: | 操作 | 方法与路径 | 说明 | |---|---|---| | Get User Quota | `GET /admin/user?quota&uid="a-type=user` | 需要 `users=read` | | Set User Quota | `PUT /admin/user?quota&uid="a-type=user` | 需要 `users=write`。**请求体内容必须包含对应读操作所编码的配额设置的 JSON 表示** | | Get Bucket Quota | `GET /admin/user?quota&uid="a-type=bucket` | 需要 `users=read` | | Set Bucket Quota | `PUT /admin/user?quota&uid="a-type=bucket` | 需要 `users=write`。请求体同上 | | Set Quota for an Individual Bucket | `PUT /admin/bucket?quota&uid=&bucket=` | 需要 `buckets=write`。请求体同上 | | Set Account Quota | `PUT /admin/account?quota&id="a-type=account` | 需要 `accounts=write` | | Set Bucket Quota under an Account | `PUT /admin/account?quota&id="a-type=bucket` | 需要 `accounts=write` | ### 7.29 Rate Limit(限流) Admin Operations API 允许在 user、bucket 上设置/获取限流配置,以及全局限流配置。限流包括:每分钟的最大操作数和/或字节数(区分读/写),作用于 bucket 和/或 user,以及最大存储大小(MB)。 **能力要求**:查看需 `ratelimit=read`;设置/修改/禁用需 `ratelimit=write`。 **合法参数**: | 参数 | 说明 | |---|---| | `bucket` | 为某 bucket 指定限流 | | `uid` | 为某 user 指定限流 | | `max-read-bytes` | 每分钟最大读字节数。`0` 禁用 | | `max-write-bytes` | 每分钟最大写字节数。`0` 禁用 | | `max-read-ops` | 每分钟最大读操作次数。`0` 禁用 | | `max-write-ops` | 每分钟最大写操作次数。`0` 禁用 | | `global` | 是否指定全局限流,值为 `'True'` 或 `'False'` | | `ratelimit-scope` | 限流作用域,可选 `bucket`、`user`、`anonymous`。**`anonymous` 仅对设置 global 配置有效** | | `enabled` | 是否启用限流,值为 `'True'` 或 `'False'` | **各操作(源文原文语法)**: | 操作 | 语法 | 所需 caps | |---|---|---| | Get User Rate Limit | `GET /{admin}/ratelimit?ratelimit-scope=user&uid=` | `ratelimit=read` | | Set User Rate Limit | `POST /{admin}/ratelimit?ratelimit-scope=user&uid=<[&max-read-bytes=][&max-write-bytes=][&max-read-ops=][&max-write-ops=][enabled=]>` | `ratelimit=write` | | Get Bucket Rate Limit | `GET /{admin}/ratelimit?bucket=&ratelimit-scope=bucket` | `users=read`(源文如此表述) | | Set Rate Limit for an Individual Bucket | `POST /{admin}/ratelimit?bucket=&ratelimit-scope=bucket<[&max-read-bytes=][&max-write-bytes=][&max-read-ops=][&max-write-ops=]>` | `ratelimit=write` | | Get Global Rate Limit | `GET /{admin}/ratelimit?global=` | `ratelimit=read` | | Set Global User Rate Limit | `POST /{admin}/ratelimit?ratelimit-scope=user&global=<[&max-read-bytes=][&max-write-bytes=][&max-read-ops=][&max-write-ops=][enabled=]>` | `ratelimit=write` | | Set Global Rate Limit Bucket | `POST /{admin}/ratelimit?ratelimit-scope=bucket&global=<[&max-read-bytes=][&max-write-bytes=][&max-read-ops=][&max-write-ops=]>` | `ratelimit=write` | | Set Global Anonymous User Rate Limit | `POST /{admin}/ratelimit?ratelimit-scope=anon&global=<[&max-read-bytes=][&max-write-bytes=][&max-read-ops=][&max-write-ops=][enabled=]>` | `ratelimit=write` | ### 7.30 Standard Error Responses | 错误 | 描述 | Code | |---|---|---| | `AccessDenied` | Access denied | 403 Forbidden | | `InternalError` | Internal server error | 500 Internal Server Error | | `NoSuchUser` | User does not exist | 404 Not Found | | `NoSuchBucket` | Bucket does not exist | 404 Not Found | | `NoSuchKey` | No such access key | 404 Not Found | ### 7.31 绑定库(Binding libraries) 官方在 `adminops.rst` 末尾列出的第三方 Admin Ops API 绑定库: | 语言 | 项目 | |---|---| | Golang | `ceph/go-ceph`、`IrekFasikhov/go-rgwadmin`、`QuentinPerez/go-radosgw` | | Java | `twonote/radosgw-admin4j` | | PHP | `lbausch/php-ceph-radosgw-admin`、`myENA/php-rgw-api` | | Python | `UMIACS/rgwadmin`、`valerytschopp/python-radosgw-admin` | > 引自:[Admin Ops API](https://docs.ceph.com/en/tentacle/radosgw/adminops/) --- ## 八、账号(User Accounts) 来源:`account.rst` 全文(11KB)。`versionadded:: Squid` ### 8.1 account 是什么 Ceph 对象网关支持 **user accounts** 作为**可选特性**,用于实现类似 **AWS IAM** 的 Users、Groups、Roles 的自助管理。 **Account Root User(账号根用户)**: - 每个 account 由一个 **account root user** 管理。 - 与普通 user、role 一样,**account 与 account root user 必须由管理员使用 `radosgw-admin` 或 Admin Ops API 创建**。 - account root user 对 account 拥有的所有资源有默认权限。 - root user 的凭据(access/secret key)可用于 **IAM API** 创建额外的 IAM user 与 role,以配合 S3 API 使用,并管理其 access key 与 policy。 - 官方建议:**account owner 应把 root user 只用于管理**,并为具体应用创建具有细粒度权限的 user 与 role。 - ⚠️ 警告:虽然 account root user 访问 account 内资源**不需要** IAM policy,但**可以**添加显示 Deny 的策略阻止其访问。使用 Deny 语句要谨慎。 ### 8.2 account 与 user 的区别(核心差异表) | 维度 | 普通(非 account)user | account 下的 user / role | |---|---|---| | 资源归属 | 该 user 自己拥有其创建的 bucket 与上传的对象 | 资源由 **account 本身**拥有 | | S3 ACL 中的 owner/grantee | 该 user | **account id** | | `s3:ListBuckets` 可见性 | 只有该 owner user 能看到 | **该 account 下的任何 user 或 role** 都能看到 | | 用量统计与配额执行 | 作用于单个 user | 作用于 **account 整体**,而非其各个 user | | 默认权限 | 允许创建 bucket 与上传对象 | **默认无任何权限**(start with no permissions at all) | **IAM Policy 的必要性**:在 account user 能执行 API 操作之前,**必须**添加某些 policy 允许之。account root user 可以通过以下几种方式为其 user 添加 identity policy: | 方式 | 使用的 action | |---|---| | 直接给用户加 policy | `iam:PutUserPolicy`、`iam:AttachUserPolicy` | | 创建 IAM group 并加组策略,再把用户加入组 | `iam:PutGroupPolicy`、`iam:AttachGroupPolicy` + `iam:AddUserToGroup`;加入组的用户继承组的全部 policy | | 创建 IAM role 并加角色策略,用户 assume 该 role | `iam:PutRolePolicy`、`iam:AttachRolePolicy` + `sts:AssumeRole` / `sts:AssumeRoleWithWebIdentity`;assume 该 role 的用户继承 role 的全部 policy | 这些 identity policy 的求值遵循 AWS 的 `Evaluating policies within a single account` 与 `Cross-account policy evaluation logic` 规则。 ### 8.3 Account IDs - 为避免歧义,Account ID 采用特殊格式:**字符串 `RGW` + 17 位数字**,例如 `RGW33567154695143645`。 - 创建 account 时若未指定 ID,会**随机生成**一个符合该格式的 ID。 - Account ID 常见于 IAM policy 文档的 **ARN** 中。例如 `arn:aws:iam::RGW33567154695143645:user/A` 指该 account 中名为 A 的 IAM 用户。**Ceph 对象网关在该位置也支持 tenant 名。** - Account ID 也可以用在 ACL 中类型为 **`CanonicalUser`** 的 `Grantee` 上(此处同样支持 User ID)。 **Principals 的差异**: | 场景 | Principal ARN 形式 | 对应 radosgw-admin 参数 | |---|---|---| | account 之外 | `arn:aws:iam:::user/uid` 或 `arn:aws:iam::tenantname:user/uid` | `uid` 对应 `--uid` | | account 之内(account user) | `arn:aws:iam::RGW33567154695143645:user/name`,用**用户名** | `name` 对应 `--display-name` | > Account user **继续匹配 tenant 形式**,这样当用户被迁入 account 时已有 policy 仍能工作。 ### 8.4 租户隔离(Tenant Isolation) - 与 user 一样,account 可以**可选地**属于某个 tenant,以实现 bucket 的命名空间隔离。例如 tenant "a" 下可以有一个名为 "acct" 的 account,tenant "b" 下也可以有一个名为 "acct" 的不同 account。 - **一个带 tenant 的 account 只能包含同名的 tenant 下的 user。** - **无论 tenant 如何,account ID 与 email 地址必须全局唯一。** ### 8.5 账号操作命令 | 操作 | 命令 | |---|---| | 创建 account | `radosgw-admin account create [--account-name={name}] [--account-id={id}] [--email={email}]` | | 创建 account root user | `radosgw-admin user create --uid={userid} --display-name={name} --account-id={accountid} --account-root --gen-secret --gen-access-key` | | 删除 account | `radosgw-admin account rm --account-id={accountid}` | | 查看 account 统计 | `radosgw-admin account stats --account-id={accountid} --sync-stats` | | 启用 account 配额 | `radosgw-admin quota set --quota-scope=account --account-id={accountid} --max-size=10G` + `radosgw-admin quota enable --quota-scope=account --account-id={accountid}` | | 启用 account 的 bucket 配额 | `radosgw-admin quota set --quota-scope=bucket --account-id={accountid} --max-objects=1000000` + `radosgw-admin quota enable --quota-scope=bucket --account-id={accountid}` | | 把已有 user 迁入 account | `radosgw-admin user modify --uid={userid} --account-id={accountid}` | 完整示例: ```bash # 1) 创建账号 radosgw-admin account create --account-name=acct1 --email=acct1@example.com # 2) 创建该账号的 root user radosgw-admin user create --uid=acct1root --display-name="Acct1 Root" \ --account-id=RGW00000000000000001 --account-root --gen-secret --gen-access-key # 3) 查看账号统计 radosgw-admin account stats --account-id=RGW00000000000000001 --sync-stats # 4) 设置账号配额并启用 radosgw-admin quota set --quota-scope=account --account-id=RGW00000000000000001 --max-size=10G radosgw-admin quota enable --quota-scope=account --account-id=RGW00000000000000001 # 5) 设置账号的 bucket 级配额并启用 radosgw-admin quota set --quota-scope=bucket --account-id=RGW00000000000000001 --max-objects=1000000 radosgw-admin quota enable --quota-scope=bucket --account-id=RGW00000000000000001 # 6) 删除账号 radosgw-admin account rm --account-id=RGW00000000000000001 ``` ### 8.6 迁移已有用户到 account ```bash radosgw-admin user modify --uid={userid} --account-id={accountid} ``` **迁移注意事项(官方 note / warning 原文要点)**: 1. **该用户的所有 bucket 的所有权将转移给 account。** 2. **account 成员身份是永久的。一旦加入,用户无法从其 account 中移除。** 3. **IAM User API 对 `UserName` 的格式有额外要求**,在把用户迁入 account 时会被强制检查。若迁移失败并报 "UserName contains invalid characters",应把 `--display-name` 修改为匹配 `[\w+=,.@-]+`。 4. ⚠️ **该用户的 notification topics 的所有权不会转移给 account。** 通知仍然工作,但这些 topic 对 SNS Topic API 不再可见。topic 及其关联的 bucket notification 需要另行迁移(见下)。 5. 因为 account user 默认无任何权限,**必须**添加某些 identity policy 以恢复用户原有权限。 6. 另一种做法:为每个已有用户创建一个新的 account,此时可以加 `--account-root` 选项让每个用户成为其 account 的 root user。 #### 迁移 Notification Topics 的步骤 Account topics **仅在启用 `notification_v2` feature 时**才受支持(详见 `radosgw-notifications` 与 `Supported Zone Features`,属第 12 册/第 10 册范畴)。 1. **迁移影响**:非 account user 迁入 account 后,其已有 notification topics 仍可通过 **RADOS Gateway admin API** 访问,但用户**无法通过 SNS Topic API 访问**它们。尽管如此,topic 仍可用,bucket notification 仍会按预期投递。 2. **重建 topics**:account user 应使用**相同的名字**重新创建 topic。旧 topic(现已不可访问)与新的 account-owned topic 可以共存且互不干扰。 3. **更新 bucket notification 配置**:订阅了旧 user-owned topic 的 bucket 应更新为使用新的 account-owned topic。**为避免重复通知,应保持相同的 notification ID。** 旧配置: ```json {"TopicConfigurations": [{ "Id": "ID1", "TopicArn": "arn:aws:sns:default::topic1", "Events": ["s3:ObjectCreated:*"]}]} ``` 新配置(其中 `RGW00000000000000001` 是 account ID,`topic1` 是 topic 名,`ID1` 是 notification ID): ```json {"TopicConfigurations": [{ "Id": "ID1", "TopicArn": "arn:aws:sns:default:RGW00000000000000001:topic1", "Events": ["s3:ObjectCreated:*"]}]} ``` 4. **移除旧 topics**:一旦没有 bucket 订阅旧 user-owned topic,可由 admin 移除: ```bash radosgw-admin topic rm --topic topic1 ``` ### 8.7 Account Root User 实操示例(awscli) 官方给出的完整流程(源文原文): ```bash # 1) 为 account root user 创建 profile $ aws --profile rgwroot configure set endpoint_url http://localhost:8000 $ aws --profile rgwroot configure AWS Access Key ID [None]: {root access key} AWS Secret Access Key [None]: {root secret key} Default region name [None]: default Default output format [None]: # 2) 创建 IAM user、添加凭据、附加 S3 访问策略 $ aws --profile rgwroot iam create-user --user-name Alice { "User": { "Path": "/", "UserName": "Alice", "UserId": "b580aa8e-14c7-4b6a-9dac-a30c640244b6", "Arn": "arn:aws:iam::RGW63136524507535818:user/Alice", "CreateDate": "2024-02-07T00:15:45.162786+00:00" } } $ aws --profile rgwroot iam create-access-key --user-name Alice { "AccessKey": { "UserName": "Alice", "AccessKeyId": "JBNLYD5BDNRVV64J02E8", "Status": "Active", "SecretAccessKey": "SnHoE700kdNuT22K8Bhy2iL3DwZU0sUSDI1gUXHr", "CreateDate": "2024-02-07T00:16:34.679316+00:00" } } $ aws --profile rgwroot iam attach-user-policy --user-name Alice \ --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess # 3) 为 S3 user 创建 profile $ aws --profile rgws3 configure set endpoint_url http://localhost:8000 $ aws --profile rgws3 configure AWS Access Key ID [None]: JBNLYD5BDNRVV64J02E8 AWS Secret Access Key [None]: SnHoE700kdNuT22K8Bhy2iL3DwZU0sUSDI1gUXHr Default region name [None]: default Default output format [None]: # 4) 用 S3 user profile 创建 bucket $ aws --profile rgws3 s3 mb s3://testbucket make_bucket: testbucket ``` > 引自:[User Accounts](https://docs.ceph.com/en/tentacle/radosgw/account/) --- ## 九、多租户(Multi-tenancy) 来源:`multitenancy.rst` 全文。`versionadded:: Jewel` ### 9.1 概念 多租户特性允许**同名**的 bucket 与 user 同时存在,方法是把它们隔离在所谓的 **`tenants`** 之下。举例用途:允许 Swift API 用户创建容易冲突的名字(如 "test" 或 "trove")的 bucket。 关键规则(源文原文): - 自 Jewel 起,**每个 user 和 bucket 都位于某个 tenant 之下**。 - 为兼容起见,提供了一个名为**空**的 "legacy" tenant。 - 每当引用 bucket 而没有显式 tenant 时,会使用**隐式 tenant**,取自执行操作的用户。 - 由于**已有用户位于 legacy tenant 之下**,他们继续像以前一样创建和访问 bucket。 - RADOS 中的对象布局以**兼容方式**扩展,确保平滑升级到 Jewel。 ### 9.2 管理带显式 tenant 的用户 **Tenant 本身没有任何操作(Tenants as such do not have any operations on them)。** 它们随着用户的管理而按需出现和消失。 创建、修改、删除带显式 tenant 的用户有两种方式: | 方式 | 说明 | |---|---| | `--tenant` 选项 | 额外的命令行选项 | | `'$'` 语法 | 在 `radosgw-admin` 命令的参数中使用 | **示例**: ```bash # 创建一个用 S3 访问的 user testx$tester # radosgw-admin --tenant testx --uid tester --display-name "Test User" --access_key TESTER --secret test123 user create # 创建一个用 Swift 访问的 user testx$tester # radosgw-admin --tenant testx --uid tester --display-name "Test User" --subuser tester:test --key-type swift --access full user create # radosgw-admin --subuser 'testx$tester:test' --key-type swift --secret test123 ``` > **注意**:带显式 tenant 的 subuser 在 shell 中**必须加引号**。 > **Tenant 名只能包含字母数字字符和下划线。** ### 9.3 访问带显式 tenant 的 bucket 客户端应用访问 bucket 时,总是使用某个特定用户的凭据。每个用户属于一个 tenant。因此**每个操作在其上下文中都有一个隐式 tenant**,在未显式指定 tenant 时使用它。只要被引用的 bucket 与引用它的用户属于同一个 tenant,就**完全保持与之前版本的兼容**——只有在访问**另一个** tenant 的 bucket 时才会出现异常。 #### 9.3.1 S3 S3 中用**冒号**分隔 tenant 与 bucket: ```text https://ep.host.dom/tenant:bucket ``` Python 示例(源文原文): ```python from boto.s3.connection import S3Connection, OrdinaryCallingFormat c = S3Connection( aws_access_key_id="TESTER", aws_secret_access_key="test123", host="ep.host.dom", calling_format = OrdinaryCallingFormat()) bucket = c.get_bucket("test5b:testbucket") ``` **重要限制(源文原文)**: - **无法通过 hostname 提供显式 tenant**。Hostname 不能包含冒号,也不能包含任何在 bucket 名中尚未合法的分隔符;用句点会产生歧义语法。因此**必须使用 bucket-in-URL-path 格式**。 - 由于**原生 S3 API 不处理多租户而 radosgw 的实现处理**,在签名 URL 与 public read ACL 场景下会有点复杂: | 场景 | 规则 | |---|---| | **签名 URL(signed URL)** | 签名 URL 包含 `AWSAccessKeyId` 查询参数,radosgw 能据此判断拥有该 bucket 的正确 user 和 tenant。因此生成签名 URL 的应用**可以只使用不带前缀的 bucket 名**(也可以选择包含前缀)。 | | **public read ACL 的 bucket** | 这种对象是被**不带任何查询参数**的 HTTP 客户端读取的,radosgw 无从判断 tenant。因此**可公开读的对象必须始终使用带 tenant 前缀的 bucket 名访问**。 | 具体例子(源文原文): - 签名 URL(对象 `bar` 在 container `foo`,tenant `7188e165c0ae4424ac68ae2e89a05c50`)——两种形式都可以: ```text http://:/foo/bar?AWSAccessKeyId=b200fb6634c547199e436a0f93c0c46e&Expires=1542890806&Signature=eok6CYQC%2FDwmQQmqvY5jTg6ehXU%3D http://:/7188e165c0ae4424ac68ae2e89a05c50:foo/bar?AWSAccessKeyId=b200fb6634c547199e436a0f93c0c46e&Expires=1542890806&Signature=eok6CYQC%2FDwmQQmqvY5jTg6ehXU%3D ``` 取决于签名生成时是否传入了 tenant 前缀。 - public read ACL(同上对象)——**必须**带前缀: ```text http://:/7188e165c0ae4424ac68ae2e89a05c50:foo/bar ``` #### 9.3.2 Swift with built-in authenticator **TBD** —— 源文原文即为 `TBD -- not in test_multen.py yet`。 #### 9.3.3 Swift with Keystone 默认配置下,**虽然原生 Swift 天然具有多租户能力,radosgw 不会为 Swift API 启用多租户**。这样做是为了确保带有 legacy bucket(即在 radosgw 支持多租户之前创建的 bucket)的环境,这些 bucket 仍保留其**双 API 能力**——既可以用 S3 也可以用 Swift 查询和修改。 若想为 Swift 启用多租户(尤其是用户只通过 OpenStack Keystone 认证的场景),应在 `ceph.conf` 中配置: ```ini rgw keystone implicit tenants = true ``` 官方文档中该选项写作 `rgw keystone implicit tenants`;其对应的实际配置项为 `rgw_keystone_implicit_tenants`(默认值取自 src/common/options/rgw.yaml.in @ v20.2.4): | 配置项 | 类型 | 默认值 | 说明 | 枚举值 | |---|---|---|---|---| | `rgw_keystone_implicit_tenants` | str | `'false'` | RGW Keystone implicit tenants creation。通过 Keystone 认证时,隐式地在与其同名的 tenant 中创建新用户。可限定为只对 S3 或 SWIFT 生效 | `false`、`true`、`swift`、`s3`、`both`、`0`、`1`、`none` | 启用后的行为(源文原文): - 任何新连接的用户(无论使用 Swift API 还是 Keystone 认证的 S3)都会促使 radosgw 创建一个名为 **`$` 是 Keystone tenant(project)UUID,例如 `7188e165c0ae4424ac68ae2e89a05c50$7188e165c0ae4424ac68ae2e89a05c50`。 - 该用户创建 Swift container 时,radosgw 内部把给定的 container 名翻译为 **`/`**,例如 `7188e165c0ae4424ac68ae2e89a05c50/foo`。这确保两个或更多不同 tenant 都创建名为 `foo` 的 container 时,radosgw 能通过 tenant 前缀透明地区分它们。 - 也可以把 `rgw keystone implicit tenants` 设为 `s3` 或 `swift`,把隐式 tenant 的效果**限定**为只对 swift 或只对 s3 生效。这主要面向以前在旧版 ceph 中使用过 implicit tenants 的用户——旧版中 implicit tenants 只作用于 swift 协议。 ### 9.4 已知限制 > 明确说明:**目前无法在其它 tenant 中创建 bucket。新建 bucket 的 owner 是从认证信息中提取的。** > 引自:[Multi-tenancy](https://docs.ceph.com/en/tentacle/radosgw/multitenancy/) --- ## 十、NFS 导出 来源:`nfs.rst` 全文(12KB)。`versionadded:: Jewel` > **注意**:使用 cephadm 或 Rook 部署时,**仅支持 NFSv4 协议**。 Ceph 对象网关的命名空间可以**通过 NFSv4 导出**,与传统的 HTTP 访问协议(S3 和 Swift)并存。具体做法是:把 Ceph 对象网关**嵌入 NFS-Ganesha NFS 服务器**中,从而提供基于文件的访问。 **管理 nfs-ganesha 集群与 rgw export 最简单也最推荐的方式是使用 `ceph nfs ...` 命令**(详见 `/mgr/nfs`,本册不展开)。 ### 10.1 librgw 与 rgw_file | 组件 | 说明 | |---|---| | `librgw` | 提供到 Ceph 对象网关服务的可加载接口,并在初始化时**实例化一个完整的 Ceph 对象网关实例** | | `rgw_file` | `librgw` 导出的、用于对 RGW bucket 与 object 进行**面向文件**访问的**有状态 API**。该 API 是通用的,但其设计**深受 NFS-Ganesha 的 FSAL(File System Abstraction Layer)API 影响**,主要就是为它设计的 | | Python bindings | 也提供了一组 Python 绑定 | ### 10.2 命名空间约定 实现遵循 **AWS 层次化命名空间约定**,把 UNIX 风格路径名映射到 S3 bucket 与 object。 | 规则 | 说明 | |---|---| | 顶层 | 由 S3 bucket 组成,表现为 **NFS 目录** | | 下级 | bucket 下的文件和目录各表现为 object,遵循 S3 的 prefix 与 delimiter 约定,**`/` 是唯一支持的路径分隔符** | | 映射示例 | NFS 客户端把 RGW 命名空间挂载在 `/nfs`,那么 NFS 命名空间中的 `/nfs/mybucket/www/index.html` 对应 bucket/container `mybucket` 中的 RGW object `www/index.html` | | 叶对象 | 无论文件还是目录,**总是**会以对应 key 名的 RGW object 物化:文件为 ``,目录为 `/` | | 非叶目录 | (如上例的 `www`)可能只由出现在一个或多个叶对象名中而**隐含存在** | | 在 NFS 内创建的目录 / 被 NFS 客户端直接操作的目录 | **总是**有叶对象表示,用于存放物化属性(如 Unix 属主和权限) | ### 10.3 支持的操作与限制 RGW NFS 接口支持对文件和目录的**大多数**操作,但有以下限制: | 限制 | 说明 | |---|---| | 不支持链接 | 包括 symlink 在内的链接都不支持 | | 不支持 NFS ACL | 但 **Unix 用户/组属主与权限是支持的** | | 目录不可移动/重命名 | 但**文件可以在目录之间移动** | | 只支持**完整、顺序**的写 I/O | 即写操作被约束为**上传(uploads)** | **顺序写的进一步说明(源文原文)**: - 许多典型的 I/O 操作(如**原地编辑文件**)必然失败,因为它们执行的是非顺序存储。 - 某些**表面上**顺序写的文件工具(如某些版本的 GNU tar)可能因为偶尔的非顺序存储而失败。 - 通过 NFS 挂载时,一般可以通过**同步挂载选项**(如 Linux 上的 `-osync`)把应用的顺序 I/O 约束为顺序写入 NFS 服务器。 - **无法同步挂载的 NFS 客户端(如 MS Windows)将无法上传文件。** ### 10.4 安全模型 RGW NFS 接口提供**混合安全模型**: | 层面 | 说明 | |---|---| | **NFS 协议安全** | 由 NFS-Ganesha 服务器提供,由 NFS 服务器与客户端协商。例如:客户端可被信任(AUTH_SYS),或被要求提供 Kerberos 用户凭据(RPCSEC_GSS)。RPCSEC_GSS 的线路安全可以是仅完整性(`krb5i`)或完整性+隐私/加密(`krb5p`)。还有各种 NFS 特有的安全与权限规则可用,例如 **root-squashing** | | **RGW/S3 凭据** | 每个 RGW NFS 挂载(即 NFS-Ganesha EXPORT)关联一组 RGW/S3 安全凭据(**NFS 不知道这些凭据**)。通过 NFS 服务器执行的所有 RGW object 操作,都将由**被访问 export 中所存凭据对应的那个 RGW 用户**执行。**目前只支持 RGW 与 RGW LDAP 凭据** | > ⚠️ 其它 RGW 认证类型(如 **Keystone**)**目前不支持**。 ### 10.5 手动配置 NFS-Ganesha 实例 每个 NFS RGW 实例都是一个**嵌入了完整 Ceph RGW 实例的 NFS-Ganesha 服务器实例**。因此 RGW NFS 的配置包含两部分: - **Ceph 与 Ceph 对象网关相关配置** → 本地 `ceph.conf` - **NFS-Ganesha 相关配置** → `ganesha.conf` #### 10.5.1 ceph.conf 必需项: - 一个合法的 `[client.rgw.{instance-name}]` 段 - 最小实例配置的合法取值,特别是**已安装且正确的 `keyring`** 其它配置变量(如 `rgw data`、`rgw backend store`)是**可选**的。 少量配置变量是 **RGW NFS 独有**的,例如 `rgw_nfs_namespace_expire_secs`。 **前端选择的特殊处理(源文原文)**:前端选择由 `librgw.so` 运行时特殊处理。**默认只启动 `rgw-nfs` 前端。** 其它前端(如 `beast`)通过 `rgw nfs frontends` 配置项启用,其语法与普通的 `rgw frontends` 选项相同。非默认前端的默认选项照常通过 `rgw frontend defaults` 指定。 | 配置项 | 类型 | 默认值(默认值取自 src/common/options/rgw.yaml.in @ v20.2.4) | 说明 | |---|---|---|---| | `rgw_nfs_frontends` | str | `rgw-nfs` | 以 librgw/nfs 方式运行时的前端配置 | | `rgw_nfs_namespace_expire_secs` | int | `5_min`(=300 秒) | RGW NFS 命名空间刷新周期。`nfs.rst` 原文:在 NFS 之外新增的对象与 bucket 会在该时间之后出现在 NFS 命名空间中,**默认 300 秒(5 分钟)**;在 Ceph 配置文件中覆盖该默认值可改变刷新速率 | | `rgw_nfs_write_completion_interval_s` | int | `10` | NFSv3 写完成判定间隔(见 10.8) | #### 10.5.2 ganesha.conf 与 RGW NFS 配合使用的**严格最小** `ganesha.conf` 包含一个 EXPORT 块,其中嵌入类型为 RGW 的 FSAL 块: ```text EXPORT { Export_ID={numeric-id}; Path = "/"; Pseudo = "/"; Access_Type = RW; SecType = "sys"; NFS_Protocols = 4; Transport_Protocols = TCP; # optional, permit unsquashed access by client "root" user #Squash = No_Root_Squash; FSAL { Name = RGW; User_Id = {s3-user-id}; Access_Key_Id ="{s3-access-key}"; Secret_Access_Key = "{s3-secret}"; } } ``` **EXPORT 块参数说明**: | 参数 | 说明 | |---|---| | `Export_ID` | 必须是整数值,例如 `"77"` | | `Path` | 对 RGW 而言应为 `"/"` | | `Pseudo` | 定义 NFSv4 pseudo root 名(**仅 NFSv4**) | | `SecType = sys;` | 允许客户端无需 Kerberos 认证即可挂载 | | `Squash = No_Root_Squash;` | 允许客户端 root 用户覆盖权限(Unix 约定)。**启用 root-squashing 时,root 用户尝试的操作会像由 NFS-Ganesha 服务器上的本地 "nobody"(和 "nogroup")用户执行一样** | **RGW FSAL 支持的 RGW 专有配置变量**(在 RGW config section 中): ```text RGW { cluster = "{cluster name, default 'ceph'}"; name = "client.rgw.{instance-name}"; ceph_conf = "/opt/ceph-rgw/etc/ceph/ceph.conf"; init_args = "-d --debug-rgw=16"; } ``` | 变量 | 说明 | |---|---| | `cluster` | 设置 Ceph 集群名(**必须与被导出的集群匹配**) | | `name` | 设置 RGW 实例名(**必须与被导出的集群匹配**) | | `ceph_conf` | 指向要使用的非默认 `ceph.conf` 文件路径 | #### 10.5.3 其它有用的 NFS-Ganesha 配置 **启用 NFSv3 与 UDP**: ```text EXPORT { ... NFS_Protocols = 3,4; Transport_Protocols = UDP,TCP; ... } ``` > 任何需要支持 NFSv3 的 EXPORT 块都应在 `NFS_Protocols` 中包含版本 3。此外,**NFSv3 是最后一个支持 UDP 传输的主要版本**;要启用 UDP,把它加入 `Transport_Protocols` 设置。 **idmapper 集成**:有一族重要选项涉及与 Linux idmapping 服务(用于跨系统规范化用户与组名)的交互,源文未提供集成细节("Details of idmapper integration are not provided here")。 **接受客户端提供的数字 UID/GID(NFSv4 默认会字符串化这些值)**——在小规模环境与试验中可能有用: ```text NFSV4 { Allow_Numeric_Owners = true; Only_Numeric_Owners = true; } ``` #### 10.5.4 排障(NFS-Ganesha 日志) NFS-Ganesha 配置问题通常通过带调试选项运行服务器来排查,由 LOG config section 控制。 日志消息按组件分组,可分别为每个组件启用日志。**组件日志的合法取值**: | 值 | 含义 | |---|---| | `FATAL` | critical errors only | | `WARN` | unusual condition | | `DEBUG` | mildly verbose trace output | | `FULL_DEBUG` | verbose trace output | 完整 LOG 配置示例(源文原文,含全部组件): ```text LOG { Components { MEMLEAKS = FATAL; FSAL = FATAL; NFSPROTO = FATAL; NFS_V4 = FATAL; EXPORT = FATAL; FILEHANDLE = FATAL; DISPATCH = FATAL; CACHE_INODE = FATAL; CACHE_INODE_LRU = FATAL; HASHTABLE = FATAL; HASHTABLE_CACHE = FATAL; DUPREQ = FATAL; INIT = DEBUG; MAIN = DEBUG; IDMAPPER = FATAL; NFS_READDIR = FATAL; NFS_V4_LOCK = FATAL; CONFIG = FATAL; CLIENTID = FATAL; SESSIONS = FATAL; PNFS = FATAL; RW_LOCK = FATAL; NLM = FATAL; RPC = FATAL; NFS_CB = FATAL; THREAD = FATAL; NFS_V4_ACL = FATAL; STATE = FATAL; FSAL_UP = FATAL; DBUS = FATAL; } # optional: redirect log output # Facility { # name = FILE; # destination = "/tmp/ganesha-rgw.log"; # enable = active; } } ``` ### 10.6 运行多个 NFS 网关 - 每个 NFS-Ganesha 实例作为一个完整的网关端点,限制是**目前一个 NFS-Ganesha 实例不能被配置为导出 HTTP 服务**。 - 与普通网关实例一样,**可以启动任意数量的 NFS-Ganesha 实例**,从集群导出相同或不同的资源。这使得 NFS-Ganesha 实例可以**集群化**。**但这并不意味着高可用(HA)。** - 当常规网关实例与 NFS-Ganesha 实例**覆盖相同的数据资源**时,这些资源既可通过标准 S3 API 访问,也可通过 NFS-Ganesha 实例导出访问。 - 可以**把 NFS-Ganesha 实例与 Ceph 对象网关实例放在同一主机上**(co-locate)。 ### 10.7 RGW vs RGW NFS | 事项 | 说明 | |---|---| | 同实例混导 | 从**同一个程序实例**同时导出 NFS 命名空间和其它 RGW 命名空间(如通过 Civetweb HTTP 前端的 S3 或 Swift)**目前不支持** | | NFS 外新增对象的可见延迟 | 在 NFS 之外添加 object 和 bucket 时,它们会在 `rgw_nfs_namespace_expire_secs` 设定的时间之后出现在 NFS 命名空间中,**默认 300 秒(5 分钟)**。在 Ceph 配置文件中覆盖该默认值可改变刷新速率 | | 导出不合规的 Swift container | 若导出的 Swift container 名不符合有效的 S3 bucket 命名要求,应在 Ceph 配置文件的 `[client.rgw]` 段把 `rgw_relaxed_s3_bucket_names` 设为 `true`。例如 Swift container 名含下划线就不是合法的 S3 bucket 名,会被拒绝,除非设置了该选项 | ### 10.8 配置 NFS 客户端 #### NFSv4 客户端 要访问该命名空间,把配置好的 NFS-Ganesha export 挂载到本地 POSIX 命名空间的期望位置。此实现有几点独特限制: - **推荐 NFS 4.1 及更高协议版本**:NFSv4 的 OPEN 与 CLOSE 操作被用于跟踪上传事务。 - **为成功上传数据,客户端必须保持写顺序**:在 Linux 与许多 Unix NFS 客户端上使用 `-osync` 挂载选项。 Linux 与部分 Unix 平台的挂载约定: ```bash # 命令行 mount -t nfs -o nfsvers=4.1,noauto,soft,sync,proto=tcp :/ ``` ```text # /etc/fstab :/ nfs noauto,soft,nfsvers=4.1,sync,proto=tcp 0 0 ``` #### NFSv3 客户端 Linux 客户端可通过提供 `nfsvers=3` 与 `noacl` 挂载选项以 NFSv3 挂载。要使用 UDP 作为传输,加入 `proto=udp`;但**首选 TCP**: ```text :/ nfs noauto,noacl,soft,nfsvers=3,sync,proto=tcp 0 0 ``` 相应地,NFS Ganesha 的 EXPORT 块中,若挂载将使用 v3 + UDP,则 Protocols 设置要包含版本 3、Transports 设置要包含 UDP。 #### NFSv3 语义 由于 **NFSv3 不向文件服务器传达客户端的 OPEN 与 CLOSE 操作**,RGW NFS 无法用这些操作标记文件上传事务的开始与结束。取而代之: - **当向某文件 offset 0 发送第一次写时,开始一次新的上传**; - **当一段时间内(默认 10 秒)没有看到对该文件的新写时,结束(finalize)该上传**。 要改变这个超时,在 Ceph 配置文件的 RGW 段中为 `rgw_nfs_write_completion_interval_s` 设置一个替代值(默认 `10`,默认值取自 src/common/options/rgw.yaml.in @ v20.2.4)。 > 引自:[Export over NFS](https://docs.ceph.com/en/tentacle/radosgw/nfs/) --- ## 十一、监控指标(Metrics) 来源:`metrics.rst` 全文(8KB)。 ### 11.1 总览 Ceph 对象网关使用 **Perf Counters** 跟踪指标。这些计数器可以是**带标签的(Labeled Perf Counters)**;带标签时,它们存放在 Ceph 对象网关特有的缓存中。 这些指标可以发送到时序数据库 **Prometheus**,以可视化集群范围的用量数据随时间的变化(例如:某个特定 bucket 上的 S3 put 操作数量)。 ### 11.2 Op Metrics(操作指标)——完整列表 以下指标与 S3 或 Swift 操作相关,**按每个 Ceph 对象网关**跟踪。 | Name | Type | Description | |---|---|---| | `put_obj_ops` | Counter | Number of put operations | | `put_obj_bytes` | Counter | Number of bytes put | | `put_obj_lat` | Gauge | Total latency of put operations | | `get_obj_ops` | Counter | Number of get operations | | `get_obj_bytes` | Counter | Number of bytes from get requests | | `get_obj_lat` | Gauge | Total latency of get operations | | `del_obj_ops` | Counter | Number of delete object operations | | `del_obj_bytes` | Counter | Number of bytes deleted | | `del_obj_lat` | Gauge | Total latency of delete object operations | | `del_bucket_ops` | Counter | Number of delete bucket operations | | `del_bucket_lat` | Gauge | Total latency of delete bucket operations | | `copy_obj_ops` | Counter | Number of copy object operations | | `copy_obj_bytes` | Counter | Number of bytes copied | | `copy_obj_lat` | Gauge | Total latency of copy object operations | | `list_object_ops` | Counter | Number of list object operations | | `list_object_lat` | Gauge | Total latency of list object operations | | `list_bucket_ops` | Counter | Number of list bucket operations | | `list_bucket_lat` | Gauge | Total latency of list bucket operations | ### 11.3 counter dump / counter schema 的三个 section `counter dump` 与 `counter schema` 命令的输出中,有三个不同的 section 展示 op metrics 及其信息: | Section | 含义 | |---|---| | `rgw_op` | 反映给定 Ceph 对象网关上**每个 op metric 的总计** | | `rgw_op_per_user` | **带标签**的 op metric 计数器,按 **user** 统计 | | `rgw_op_per_bucket` | **带标签**的 op metric 计数器,按 **bucket** 统计 | 查看方式: - op metric 的**信息**(schema)在 `counter schema` 输出的 `rgw_op` 段中; - op metric 的**数值**在 `counter dump` 输出的 `rgw_op` 段中。 `rgw_op` 段输出示例(源文原文): ```json "rgw_op": [ { "labels": {}, "counters": { "put_obj_ops": 2, "put_obj_bytes": 5327, "put_obj_lat": { "avgcount": 2, "sum": 2.818064835, "avgtime": 1.409032417 }, "get_obj_ops": 5, "get_obj_bytes": 5325, "get_obj_lat": { "avgcount": 2, "sum": 0.003000069, "avgtime": 0.001500034 }, ... "list_buckets_ops": 1, "list_buckets_lat": { "avgcount": 1, "sum": 0.002300000, "avgtime": 0.002300000 } } }, ] ``` ### 11.4 Op Metrics Labels(标签) Op metrics 也可以按 **user** 或按 **bucket** 跟踪。导出到 Prometheus 时带类似 `Bucket = {name}` 或 `User = {userid}` 的标签: ```json "rgw_op_per_bucket": [ ... { "labels": { "Bucket": "bucket1" }, "counters": { "put_obj_ops": 2, "put_obj_bytes": 5327, "put_obj_lat": { "avgcount": 2, "sum": 2.818064835, "avgtime": 1.409032417 }, "get_obj_ops": 5, "get_obj_bytes": 5325, "get_obj_lat": { "avgcount": 2, "sum": 0.003000069, "avgtime": 0.001500034 }, ... "list_buckets_ops": 1, "list_buckets_lat": { "avgcount": 1, "sum": 0.002300000, "avgtime": 0.002300000 } } }, ... ] ``` **多租户的标签**:多租户允许在不同 tenant 下创建同名的 bucket 与 user。**若 user 或 bucket 位于某个 tenant 之下,会额外加上形如 `Tenant = {tenantid}` 的标签。** **默认关闭(源文原文要点)**: > 在拥有大量 user 和 bucket 的大型系统中,把**所有**指标导出到 Prometheus 可能不可行。**因此,这些带标签指标的收集默认是禁用的。** > > 一旦启用,被跟踪的 user 与 bucket 的工作集会被加以限制,以控制内存与数据库使用。**其结果是,这些带标签指标的收集并不总是可靠的。** ### 11.5 User & Bucket Counter Caches | 目的 | 必须启用的配置项 | |---|---| | 跟踪 **by user** 的 op metrics | `rgw_user_counters_cache = true` | | 跟踪 **by bucket** 的 op metrics | `rgw_bucket_counters_cache = true` | 设置方式: ```bash ceph config set client.rgw rgw_user_counters_cache true ceph config set client.rgw rgw_bucket_counters_cache true ``` > ⚠️ **重要**:由于 op metrics 是 labeled perf counters,它们**存活在内存中**。若 Ceph 对象网关**重启或崩溃**,该网关中的所有计数器——无论在缓存中与否——**都会丢失**。 ### 11.6 缓存大小与淘汰(Eviction) - `rgw_user_counters_cache_size` 与 `rgw_bucket_counters_cache_size` 分别设置每个缓存中的条目数。 - **一旦缓存中的计数器数量大于缓存大小配置值,计数器就会被淘汰;被淘汰的是最近最少使用(LRU)的计数器。** - 举例:若 bucket 数量超出 `rgw_bucket_counters_cache_size` 达到 1,且标签为 `bucket1` 的计数器是最后被更新的,则 `bucket1` 的计数器会被淘汰。若淘汰后又对 `bucket1` 执行了被 op metrics 跟踪的 S3 操作,则缓存中 `bucket1` 的**所有指标都会从 0 重新开始**。 **缓存 sizing 的依赖因素**: 1. 集群中的 user 数量 2. 集群中的 bucket 数量 3. Ceph 对象网关的内存占用 4. Prometheus 的磁盘与内存占用 > **内存估算**:为帮助计算 Ceph 对象网关某个缓存的内存占用,需注意**每个缓存条目(包含全部 op metrics)为 1360 字节**。这是一个估算值,**如果 op metrics 列表增加或删除指标,该值会变化**。 ### 11.7 把指标发送到 Prometheus - 要把指标从 Ceph 对象网关送入时序数据库 Prometheus,**必须运行 ceph-exporter 守护进程,并配置它去 scrape Radosgw 的 admin socket**。 - ceph-exporter 守护进程以固定间隔 scrape Ceph 对象网关的 admin socket,该间隔由配置变量 **`exporter_stats_period`** 定义。 - Prometheus 自身也有可配置的 scrape 间隔(见 Prometheus 官方文档)。 ### 11.8 配置参考(Metrics) 通过 `ceph config set client.rgw CONFIG_VARIABLE VALUE` 设置: | 配置项 | 类型 | 默认值(默认值取自 src/common/options/*.yaml.in @ v20.2.4) | 含义 | |---|---|---|---| | `rgw_user_counters_cache` | bool | `false` | 启用一个 rgw perf counters 缓存,存放带 user 标签的计数器。该缓存只包含以 user 为标签的 perf counters | | `rgw_user_counters_cache_size` | uint | `10000` | user perf counters 缓存可存放的带标签 perf counters 数量 | | `rgw_bucket_counters_cache` | bool | `false` | 启用一个 rgw perf counters 缓存,存放带 bucket 标签的计数器。该缓存只包含以 bucket 为标签的 perf counters | | `rgw_bucket_counters_cache_size` | uint | `10000` | bucket perf counters 缓存可存放的带标签 perf counters 数量 | 通过 `ceph config set global CONFIG_VARIABLE VALUE` 设置(ceph-exporter 相关): | 配置项 | 类型 | 默认值(默认值取自 src/common/options/ceph-exporter.yaml.in @ v20.2.4) | 含义 | |---|---|---|---| | `exporter_stats_period` | int | `5` | 再次向 exporter server 发送请求前的等待时间(秒) | > 引自:[Metrics](https://docs.ceph.com/en/tentacle/radosgw/metrics/) --- ## 十二、配置参考(Config Reference) 来源:`config-ref.rst` 全文(13KB)+ `metrics.rst` + `nfs.rst` 中出现的配置项。 ### 12.1 使用约定(源文原文要点) 1. 以下设置可添加到 Ceph 配置文件(通常是 `ceph.conf`)的 **`[client.radosgw.{instance-name}]`** 段下。这些设置可能包含默认值;若你未在其中显式指定每个设置,则会自动采用默认值。 2. **写在 `[client.radosgw.{instance-name}]` 段下的配置变量,对未指定 instance-name 的 `rgw` 或 `radosgw-admin` 命令不生效。** 因此,希望对所有 RGW 实例或所有 `radosgw-admin` 选项生效的变量,应放到 **`[global]`** 或 **`[client]`** 段,以避免指定 instance-name。 **默认值来源说明**:下表中所有 `默认值` 列的数据均取自 `src/common/options/*.yaml.in @ v20.2.4`(本机路径 `handbook-src/options/rgw.yaml.in`、`global.yaml.in`、`ceph-exporter.yaml.in`),因为 rst 源文中的 `.. confval::` 默认值是构建期生成的占位符。凡这些 yaml.in 中也不存在的,标注「文档未明确」。 **Lifecycle 调优建议(源文原文)**: - 这两个值可根据具体工作负载调整,以进一步提高 lifecycle 处理的激进程度。 - 对于 **bucket 数量很多(数千个)** 的工作负载:**调大 `rgw_lc_max_worker`**(默认 3)。 - 对于 **单 bucket 内对象数很多(数十万个)** 的工作负载:**调大 `rgw_lc_max_wp_worker`**(默认 3)。 - ⚠️ **在调大任何一个值之前,先验证当前集群性能与 Ceph 对象网关利用率。** - ⚠️ **每个 zone 至少需有一个 RGW 守护进程启用 lifecycle 维护线程(`rgw_enable_lc_threads`)。** **Garbage Collection 说明与调优(源文原文)**: - Ceph 对象网关**立即**为新对象分配存储空间,但**在**网关把已删除/被覆盖的对象从 **bucket index** 中删除**之后的某个时刻**,才清除它们在 Ceph 存储集群中占用的空间。这个清除过程称为 **Garbage Collection(GC)**。 - 查看等待 GC 的对象队列: ```bash radosgw-admin gc list ``` > 指定 `--include-all` 可列出所有条目,包括未过期的 GC 对象。 - GC 是后台活动,可连续执行,也可在低负载时段执行,取决于管理员如何配置。**默认情况下 Ceph 对象网关连续执行 GC 操作。** - 由于 GC 操作是 Ceph 对象网关的正常运行的一部分(尤其是对象删除操作),**大多数时候都存在符合 GC 条件的对象**。 - **删除密集型工作负载**可能临时或永久超过 GC 的速率。管理员可通过以下配置参数**提高 GC 操作相对于其它操作的优先级**。 - **删除密集负载的初始调优建议**: ```ini rgw_gc_max_concurrent_io = 20 rgw_gc_max_trim_chunk = 64 ``` > ⚠️ **修改这些值需要重启 RGW 服务。** 调大后请监控集群在 GC 期间的性能,确认没有因调大而导致的不良性能问题。 > ⚠️ **每个 zone 至少需有一个 RGW 运行垃圾回收维护线程(`rgw_enable_gc_threads`)。** **Multisite 重要提示(源文原文)**:`rgw_data_log_num_shards` 与 `rgw_md_log_max_shards` 的值**在同步开始之后不应再修改**。 **QoS 说明(源文原文)**:较旧且现已非默认的 `civetweb` 前端采用**每连接一个线程**的线程模型,因此在接受连接时**自动**受 `rgw_thread_pool_size` 节流。较新且默认的 `beast` 前端在接受新连接时**不受**线程池大小限制,因此在 Nautilus 引入了 scheduler 抽象,以支持额外的请求调度方式。当前 scheduler 默认为一个 throttler,把活跃连接数限制在一个配置上限。**基于 mClock 的 QoS 限流目前处于实验阶段,不建议用于生产。** 当前 *dmclock_client* op queue 的实现把 RGW op 分为 admin、auth(swift auth、sts)、metadata、data 请求。 **D4N 说明(源文原文)**:D4N 是一种缓存架构,利用 **Redis** 通过**在 Ceph 对象网关(RGW)守护进程之间建立共享数据库**来加速 S3 对象存储操作。**D4N 架构一次只能作用于一个 Redis 实例。** 地址可配置,可通过下面的参数更改。 **Topic persistency 说明(源文原文)**:Topic persistency 会**反复推送通知直到成功**。默认行为是**无限期、尽可能频繁地推送**。通过这些设置可以控制一次不成功通知的重试时长和/或最大重试次数;两次推送重试之间的间隔通过 sleep duration 参数配置。**所有这些选项默认值为 `0`,意味着持久化保留是无限期的,通知会尽可能频繁地重试。** **Cloud Restore 说明(源文原文)**:Cloud Restore 特性目前支持把已 transition 到 S3 兼容云服务上的对象恢复到 Ceph 对象网关(RGW)。restore 请求由后台的 Restore worker thread **异步**处理。 ### 12.2 核心设置(Core Settings) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_frontends` | str | `beast port=7480` | RGW 前端(frontend)配置 | | `rgw_data` | str | `/var/lib/ceph/radosgw/$cluster-$id` | RGW 配置的备用目录路径 | | `rgw_enable_apis` | str | `s3, s3website, swift, swift_auth, admin, sts, iam, notifications` | RGW 要启用的 RESTful API 列表 | | `rgw_cache_enabled` | bool | `true` | 是否启用 RGW 元数据缓存 | | `rgw_cache_lru_size` | int | `25000` | RGW 元数据缓存中的最大条目数 | | `rgw_dns_name` | str | `(无默认值)` | RGW 使用的主机名。逗号分隔的 DNS 名列表;除非通过 zonegroup 配置,否则 bucket 虚拟主机(virtual hosting)要正常工作需要它;另见 zonegroup 内的 hostnames 设置 | | `rgw_script_uri` | str | `(无默认值)` | 请求中未设置 ``SCRIPT_URI`` 时使用的替代值 | | `rgw_request_uri` | str | `(无默认值)` | 请求中未设置 ``REQUEST_URI`` 时使用的替代值 | | `rgw_print_continue` | bool | `true` | RGW 是否支持 100-continue | | `rgw_remote_addr_param` | str | `REMOTE_ADDR` | 入站请求中携带远端地址的 HTTP header 名 | | `rgw_op_thread_timeout` | int | `10_min` | 异步 rados 协程操作的超时时间 | | `rgw_op_thread_suicide_timeout` | int | `0` | Ceph 对象网关进程自行退出前的 timeout 秒数;设为 ``0`` 表示禁用 | | `rgw_thread_pool_size` | int | `512` | RGW 请求处理线程池大小。决定使用 civetweb 或 fastcgi 前端时 RGW 能处理的并发请求数;数值越大并发能力越强,代价是资源占用更高 | | `rgw_num_control_oids` | int | `8` | 用于跨 RGW 通信的控制对象数量 | | `rgw_init_timeout` | int | `5_min` | 初始化超时 | | `rgw_mime_types_file` | str | `/etc/mime.types` | 本地 mime types 文件路径 | | `rgw_s3_success_create_obj_status` | int | `0` | 对象创建时的 HTTP 返回码覆盖值 | | `rgw_resolve_cname` | bool | `false` | 是否通过 CNAME 支持 vanity domain name | | `rgw_obj_stripe_size` | size | `4_M` | RGW 对象条带(stripe)大小 | | `rgw_extended_http_attrs` | str | `(无默认值)` | RGW 支持扩展 HTTP attrs | | `rgw_exit_timeout_secs` | int | `2_min` | RGW 关闭(shutdown)超时 | | `rgw_get_obj_window_size` | size | `16_M` | RGW 对象读取窗口大小 | | `rgw_get_obj_max_req_size` | size | `4_M` | RGW 对象读取 chunk 大小 | | `rgw_multipart_min_part_size` | size | `5_M` | S3 multipart-upload 的最小 part 大小 | | `rgw_relaxed_s3_bucket_names` | bool | `false` | 是否启用放宽的 S3 bucket 命名规则 | | `rgw_list_buckets_max_chunk` | int | `1000` | 单次列举操作中可获取的 bucket 最大数量 | | `rgw_override_bucket_index_max_shards` | uint | `0` | 新建 bucket 的默认 bucket index 分片数。该值会覆盖 zone 中保存的 ``bucket_index_max_shards``。**官方建议在 zone 中设置**,因为它对该 zone 内所有 radosgw 守护进程全局生效 | | `rgw_curl_wait_timeout_ms` | int | `1000` | 某些 ``curl`` 调用的超时时间(毫秒) | | `rgw_copy_obj_progress` | bool | `true` | copy 操作过程中是否发送进度报告 | | `rgw_copy_obj_progress_every_bytes` | size | `1_M` | 每传输多少字节后发送一次 copy-object 进度信息 | | `rgw_max_copy_obj_concurrent_io` | int | `10` | 执行 copy_obj 时并发处理的 refcount 操作数量 | | `rgw_admin_entry` | str | `admin` | 访问 RGW RESTful admin API 的路径前缀 | | `rgw_content_length_compat` | bool | `false` | 多个 content length header 的兼容性处理 | | `rgw_bucket_quota_ttl` | int | `10_min` | Bucket quota 统计的缓存 TTL | | `rgw_user_quota_bucket_sync_interval` | int | `3_min` | User quota 的 bucket 同步间隔 | | `rgw_user_quota_sync_interval` | int | `1_day` | User quota 同步间隔 | | `rgw_bucket_default_quota_max_objects` | int | `-1` | Bucket 中最大对象数的默认配额 | | `rgw_bucket_default_quota_max_size` | int | `-1` | Bucket 总大小的默认配额 | | `rgw_user_default_quota_max_objects` | int | `-1` | User 的最大对象数配额 | | `rgw_user_default_quota_max_size` | int | `-1` | User 的最大容量配额 | | `rgw_account_default_quota_max_objects` | int | `-1` | Account 的最大对象数配额 | | `rgw_account_default_quota_max_size` | int | `-1` | Account 的最大容量配额 | | `rgw_verify_ssl` | bool | `true` | RGW 连接远端 HTTP 服务器时是否校验 SSL | | `rgw_max_chunk_size` | size | `4_M` | RGW 最大 chunk 大小。chunk size 是 RGW 访问 RADOS 对象时发给 OSD 的请求大小;读写单请求永不超过此值;**它也定义了 RGW HEAD 对象的大小**(head 操作需原子)。写入默认 storage class 时最多有这么多载荷数据与元数据一起存在 head 对象;写入**非默认** storage class 时 HEAD RADOS 对象仍在默认 storage class 的 pool 中,但**不内联**载荷数据 | ### 12.3 Lifecycle Settings(生命周期) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_lc_max_worker` | int | `3` | 并行运行的 LCWorker 任务数量(大量 bucket 场景可调大) | | `rgw_lc_max_wp_worker` | int | `3` | 每个 LCWorker 的 workpool 线程数(单 bucket 内对象极多可调大) | | `rgw_enable_lc_threads` | bool | `true` | 是否启用 lifecycle 维护线程。**每个 zone 至少需要一个 RGW 守护进程开启此项** | ### 12.4 Garbage Collection Settings(垃圾回收) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_gc_max_objs` | int | `32` | 垃圾回收数据的分片(shard)数量 | | `rgw_gc_obj_min_wait` | int | `2_hr` | 垃圾回收对象的过期时间 | | `rgw_gc_processor_max_time` | int | `1_hr` | GC processor 可以 lease 某个 shard 的时长 | | `rgw_gc_processor_period` | int | `1_hr` | 垃圾回收周期运行时长 | | `rgw_gc_max_concurrent_io` | int | `10` | 垃圾回收的最大并发 RADOS IO 操作数 | | `rgw_gc_max_trim_chunk` | int | `16` | 单次操作中从 garbage collector log 移除的最大 key 数(**删除密集负载调优建议值:64**) | | `rgw_enable_gc_threads` | bool | `true` | 是否启用垃圾回收维护线程。**每个 zone 至少需要一个 RGW 开启** | ### 12.5 Multisite Settings(多站点) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_zone` | str | `(无默认值)` | Zone 名称 | | `rgw_zonegroup` | str | `(无默认值)` | Zonegroup 名称 | | `rgw_realm` | str | `(无默认值)` | 网关实例所属 realm 名。若未设置 realm,可用 ``radosgw-admin realm default`` 命令配置集群级默认值 | | `rgw_run_sync_thread` | bool | `true` | 是否运行 sync 线程 | | `rgw_data_log_window` | int | `30` | Data log 时间窗口 | | `rgw_data_log_changes_size` | int | `1000` | Data log 中待处理变更的最大条数 | | `rgw_data_log_num_shards` | int | `128` | Data log 分片数(**同步开始后不应再修改**) | | `rgw_md_log_max_shards` | int | `64` | RGW metadata log 分片数(**同步开始后不应再修改**) | | `rgw_data_sync_poll_interval` | int | `20` | 多站点增量同步追平某个 datalog shard 后,等待多少秒再轮询更多变更 | | `rgw_meta_sync_poll_interval` | int | `20` | 多站点增量同步追平某个 mdlog shard 后,等待多少秒再轮询更多变更 | | `rgw_bucket_sync_spawn_window` | int | `20` | bucket sync 愿意并行处理的最大条目数(每个远端 bilog shard) | | `rgw_data_sync_spawn_window` | int | `20` | data sync 愿意并行处理的最大条目数(每个远端 datalog shard) | | `rgw_meta_sync_spawn_window` | int | `20` | metadata sync 愿意并行处理的最大条目数(每个远端 mdlog shard) | ### 12.6 S3 Settings | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_s3_auth_use_ldap` | bool | `false` | S3 认证是否使用 LDAP | ### 12.7 Swift Settings | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_enforce_swift_acls` | bool | `true` | RGW 是否强制实施 swift acls | | `rgw_swift_tenant_name` | str | `(无默认值)` | Swift tenant 名 | | `rgw_swift_token_expiration` | int | `1_day` | 通过 RGW Swift auth 生成的 token 的过期时间(秒) | | `rgw_swift_url` | str | `(无默认值)` | Swift-auth storage URL | | `rgw_swift_url_prefix` | str | `swift` | Swift URL 前缀 | | `rgw_swift_auth_url` | str | `(无默认值)` | Swift auth URL | | `rgw_swift_auth_entry` | str | `auth` | Swift auth URL 前缀 | | `rgw_swift_account_in_url` | bool | `false` | Swift account 是否编码在 URL 中 | | `rgw_swift_versioning_enabled` | bool | `false` | 是否启用 Swift versioning | | `rgw_trust_forwarded_https` | bool | `false` | 是否信任 Forwarded 与 X-Forwarded-Proto header | ### 12.8 Logging Settings(日志) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_log_nonexistent_bucket` | bool | `false` | RGW 是否记录对不存在 bucket 的操作 | | `rgw_log_object_name` | str | `'%Y-%m-%d-%H-%i-%n'` | Ops log 对象名格式 | | `rgw_log_object_name_utc` | bool | `false` | Ops log 对象名是否基于 UTC | | `rgw_usage_max_shards` | int | `32` | Usage log 的分片数 | | `rgw_usage_max_user_shards` | int | `1` | Usage log 中单个用户的分片数 | | `rgw_enable_ops_log` | bool | `false` | 是否启用 ops log | | `rgw_enable_usage_log` | bool | `false` | 是否启用 usage log | | `rgw_ops_log_rados` | bool | `false` | Ops log 是否使用 RADOS | | `rgw_ops_log_socket_path` | str | `(无默认值)` | Ops log 的 Unix domain socket 路径 | | `rgw_ops_log_data_backlog` | size | `5_M` | Ops log socket 的 backlog 大小 | | `rgw_usage_log_flush_threshold` | int | `1024` | Usage log 刷盘前累积的条目数 | | `rgw_usage_log_tick_interval` | int | `30` | Usage log 刷盘周期间的秒数 | | `rgw_log_http_headers` | str | `(无默认值)` | 要记录的 HTTP header 列表 | ### 12.9 Keystone Settings | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_keystone_url` | str | `(无默认值)` | Keystone 服务器的 URL | | `rgw_keystone_admin_domain` | str | `(无默认值)` | Keystone admin 用户 domain(Keystone v3) | | `rgw_keystone_admin_project` | str | `(无默认值)` | Keystone admin 用户 project(Keystone v3) | | `rgw_keystone_admin_token` | str | `(无默认值)` | **已废弃**:用于 Keystone 请求的 admin token(共享密钥) | | `rgw_keystone_admin_token_path` | str | `(无默认值)` | 包含 admin token(共享密钥)的文件路径 | | `rgw_keystone_admin_tenant` | str | `(无默认值)` | Keystone admin 用户 tenant | | `rgw_keystone_admin_user` | str | `(无默认值)` | Keystone admin 用户 | | `rgw_keystone_admin_password` | str | `(无默认值)` | **已废弃**:Keystone admin 密码 | | `rgw_keystone_admin_password_path` | str | `(无默认值)` | 包含 Keystone admin 密码的文件路径 | | `rgw_keystone_accepted_roles` | str | `Member, admin` | 只有具备这些角色之一的用户在 Keystone 认证时才会被服务 | | `rgw_keystone_token_cache_size` | int | `10000` | Keystone token 缓存大小 | | `rgw_keystone_verify_ssl` | bool | `true` | RGW 是否校验 Keystone 服务器的 SSL 证书 | | `rgw_keystone_service_token_enabled` | bool | `false` | 是否允许 service token 使用已过期的 Keystone auth token | | `rgw_keystone_service_token_accepted_roles` | str | `admin` | 只有具备这些角色之一的用户才是合法的 service user | | `rgw_keystone_expired_token_cache_expiration` | int | `3600` | 过期 token 的过期时间上,在当前时间基础上增加的秒数 | | `rgw_keystone_implicit_tenants` | str | `'false'` | RGW Keystone 隐式 tenant 创建。通过 Keystone 认证时,在其同名 tenant 中隐式创建新用户;可限定只对 S3 或 SWIFT 生效 | ### 12.10 Server-side encryption Settings(服务端加密) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_crypt_s3_kms_backend` | str | `barbican` | SSE-KMS 加密密钥存放在哪里。支持的 KMS 系统有 OpenStack Barbican(``barbican``,默认)与 HashiCorp Vault(``vault``) | ### 12.11 Barbican Settings | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_barbican_url` | str | `(无默认值)` | Barbican 服务器的 URL | | `rgw_keystone_barbican_user` | str | `(无默认值)` | 访问 barbican secret 的 Keystone 用户 | | `rgw_keystone_barbican_password` | str | `(无默认值)` | barbican 用户的 Keystone 密码 | | `rgw_keystone_barbican_tenant` | str | `(无默认值)` | Keystone barbican 用户 tenant(Keystone v2.0) | | `rgw_keystone_barbican_project` | str | `(无默认值)` | Keystone barbican 用户 project(Keystone v3) | | `rgw_keystone_barbican_domain` | str | `(无默认值)` | Keystone barbican 用户 domain | ### 12.12 HashiCorp Vault Settings | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_crypt_vault_auth` | str | `token` | 与 Vault 配合使用的认证方式类型 | | `rgw_crypt_vault_token_file` | str | `(无默认值)` | 若认证方式为 ``token``,则提供 token 文件路径(出于安全考虑,该文件应只对 Rados Gateway 可读) | | `rgw_crypt_vault_addr` | str | `(无默认值)` | Vault 服务器基地址 | | `rgw_crypt_vault_prefix` | str | `(无默认值)` | Vault secret URL 前缀,可用于把访问限制在 Vault secret 空间的某个子集 | | `rgw_crypt_vault_secret_engine` | str | `transit` | 用于获取加密密钥的 Vault Secret Engine | | `rgw_crypt_vault_namespace` | str | `(无默认值)` | 用于选择租户的 Vault Namespace | ### 12.13 SSE-S3 Settings | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_crypt_sse_s3_backend` | str | `vault` | SSE-S3 加密密钥存放在哪里。唯一合法选择是 HashiCorp Vault(``vault``) | | `rgw_crypt_sse_s3_vault_secret_engine` | str | `transit` | 用于获取加密密钥的 Vault Secret Engine | | `rgw_crypt_sse_s3_key_template` | str | `"%bucket_id"` | Vault 中 per-bucket SSE-S3 key 的模板 | | `rgw_crypt_sse_s3_vault_auth` | str | `token` | SSE-S3 与 Vault 配合使用的认证方式类型 | | `rgw_crypt_sse_s3_vault_token_file` | str | `(无默认值)` | 若认证方式为 ``token``,则提供 token 文件路径(出于安全考虑,该文件应只对 Rados Gateway 可读) | | `rgw_crypt_sse_s3_vault_addr` | str | `(无默认值)` | SSE-S3 Vault 服务器基地址 | | `rgw_crypt_sse_s3_vault_prefix` | str | `(无默认值)` | SSE-S3 Vault secret URL 前缀,可把访问限制在 Vault secret 空间的某个子集 | | `rgw_crypt_sse_s3_vault_namespace` | str | `(无默认值)` | 用于选择租户的 Vault Namespace | | `rgw_crypt_sse_s3_vault_verify_ssl` | bool | `true` | RGW 是否校验 vault 服务器的 SSL 证书 | | `rgw_crypt_sse_s3_vault_ssl_cacert` | str | `(无默认值)` | 访问 vault 服务器的自定义 CA 证书路径 | | `rgw_crypt_sse_s3_vault_ssl_clientcert` | str | `(无默认值)` | 访问 vault 服务器的自定义客户端证书路径 | | `rgw_crypt_sse_s3_vault_ssl_clientkey` | str | `(无默认值)` | 客户端证书所需私钥的路径 | ### 12.14 QoS settings(服务质量/调度) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_max_concurrent_requests` | int | `1024` | 最大并发 HTTP 请求数 | | `rgw_scheduler_type` | str | `throttler` | dmclock scheduler 类型,默认 ``throttler``;另一个合法值 ``dmclock`` 是实验性的 | | `rgw_dmclock_auth_res` | float | `200` | auth 请求的 mclock reservation(保留值) | | `rgw_dmclock_auth_wgt` | float | `100` | auth 请求的 mclock weight(权重) | | `rgw_dmclock_auth_lim` | float | `0` | auth 请求的 mclock limit(上限) | | `rgw_dmclock_admin_res` | float | `100` | admin 请求的 mclock reservation | | `rgw_dmclock_admin_wgt` | float | `100` | admin 请求的 mclock weight | | `rgw_dmclock_admin_lim` | float | `0` | admin 请求的 mclock limit | | `rgw_dmclock_data_res` | float | `500` | object data 请求的 mclock reservation | | `rgw_dmclock_data_wgt` | float | `500` | object data 请求的 mclock weight | | `rgw_dmclock_data_lim` | float | `0` | object data 请求的 mclock limit | | `rgw_dmclock_metadata_res` | float | `500` | metadata 请求的 mclock reservation | | `rgw_dmclock_metadata_wgt` | float | `500` | metadata 请求的 mclock weight | | `rgw_dmclock_metadata_lim` | float | `0` | metadata 请求的 mclock limit | ### 12.15 D4N Settings(分布式缓存) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_d4n_address` | str | `127.0.0.1:6379` | D4N Redis 连接的地址 | | `rgw_d4n_l1_datacache_persistent_path` | str | `/tmp/rgw_d4n_datacache/` | 本地缓存对象数据的存放路径 | | `rgw_d4n_l1_datacache_size` | size | `1_G` | datacache 在磁盘上的最大容量 | | `rgw_d4n_l1_evict_cache_on_start` | bool | `true` | 启动时是否清空持久化 datacache 的内容 | | `rgw_d4n_l1_fadvise` | int | `4` | 缓存文件访问模式的 ``posix_fadvise()`` flag | | `rgw_d4n_libaio_aio_threads` | int | `20` | libaio 可使用的最大工作线程数 | | `rgw_d4n_libaio_aio_num` | int | `64` | libaio 预期入队的最大并发 I/O 请求数 | | `rgw_lfuda_sync_frequency` | int | `60` | LFUDA 变量的同步频率(秒) | | `rgw_d4n_l1_datacache_address` | str | `127.0.0.1:6379` | 本地 Redis 缓存地址 | ### 12.16 Topic persistency settings(通知持久化) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_topic_persistency_time_to_live` | uint | `0` | 持久化 topic 的按时间保留时长(秒) | | `rgw_topic_persistency_max_retries` | uint | `0` | 持久化通知的最大尝试发送次数。**值为 1 表示不重试,值为 0 表示无限重试** | | `rgw_topic_persistency_sleep_duration` | uint | `0` | 同一条持久化通知两次尝试之间的最小时间间隔(秒)。**实际间隔可能更长** | ### 12.17 Cloud Restore settings(云回调) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_restore_max_objs` | int | `32` | restore 处理的分片数 | | `rgw_restore_lock_max_time` | int | `90` | restore 处理持锁的最长时间(秒)。**官方文档未提供 desc,含义由上下文推断** | | `rgw_restore_processor_period` | int | `15_min` | Restore 周期运行时长 | ### 12.18 Metrics(监控指标,来自 metrics.rst) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_user_counters_cache` | bool | `false` | 是否启用 rgw perf counters 缓存,用于带 user 标签的计数器。该缓存只包含以 user 为标签的 perf counters | | `rgw_user_counters_cache_size` | uint | `10000` | user perf counters 缓存可存放的带标签 perf counters 数量 | | `rgw_bucket_counters_cache` | bool | `false` | 是否启用 rgw perf counters 缓存,用于带 bucket 标签的计数器。该缓存只包含以 bucket 为标签的 perf counters | | `rgw_bucket_counters_cache_size` | uint | `10000` | bucket perf counters 缓存可存放的带标签 perf counters 数量 | | `exporter_stats_period` | 文档未明确 | `文档未明确` | 再次向 exporter server 发送请求前的等待时间(秒) | ### 12.19 NFS Settings(来自 nfs.rst) | 配置项 | 类型 | 默认值 | 含义 | |---|---|---|---| | `rgw_nfs_frontends` | str | `rgw-nfs` | 以 librgw/nfs 方式运行时的前端配置。逗号分隔的前端配置列表;默认只启动 ``rgw-nfs`` 前端 | | `rgw_nfs_namespace_expire_secs` | int | `5_min` | NFS 命名空间中缓存条目的过期时间。`nfs.rst` 说明:在 NFS 之外新增的 object/bucket 会在该时间后出现在 NFS 命名空间中,**默认 300 秒(5 分钟)** | | `rgw_nfs_write_completion_interval_s` | int | `10` | NFSv3 下判定一次上传完成的静默间隔(秒),默认 10 秒 | > 引自:[Ceph Object Gateway Config Reference](https://docs.ceph.com/en/tentacle/radosgw/config-ref/) --- ## 十三、排障(Troubleshooting) 来源:`troubleshooting.rst` 全文(7KB)。按「现象 → 原因 → 解决」逐场景列出。 ### 13.1 场景一:网关无法启动(The Gateway Won't Start) | 项目 | 内容 | |---|---| | **现象** | 无法启动网关(即**不存在**已有的 `pid`) | | **原因** | 存在**另一个用户**留下的 `.asok` 文件。这可能发生在:你以 `root` 用户启动进程,而启动脚本试图以 `www-data` 或 `apache` 用户启动进程,此时已存在的 `.asok` 阻止了脚本启动守护进程 | | **解决** | 若存在其它用户的 `.asok` 文件且**没有正在运行的 `pid`**,则**删除该 `.asok` 文件**并重试启动进程 | **辅助诊断**:`radosgw` init 脚本(`/etc/init.d/radosgw`)提供了 verbose 参数,可提供一些线索: ```bash /etc/init.d/radosgw start -v ``` 或: ```bash /etc/init.d radosgw start --verbose ``` ### 13.2 场景二:HTTP 请求错误(HTTP Request Errors) | 项目 | 内容 | |---|---| | **现象** | 出现 HTTP 请求错误,尤其是 **500 错误** | | **原因** | 500 错误通常表明**与 `radosgw` 守护进程通信有问题** | | **排查/解决** | 1) 检查 Web 服务器自身的 access log 与 error log(这通常是定位问题的第一步);2) 确保守护进程**正在运行**;3) 确保其 **socket 路径已配置**;4) 确保 Web 服务器在**正确的位置**寻找它 | ### 13.3 场景三:`radosgw` 进程崩溃(Crashed radosgw process) | 项目 | 内容 | |---|---| | **现象** | 从 Web 服务器(apache、nginx 等)看到 **500 错误** | | **原因** | `radosgw` 进程已死 | | **恢复** | **简单地重启 `radosgw` 即可恢复服务** | | **定位根因** | 检查 `/var/log/ceph` 中的日志,和/或 core file(如果有生成) | ### 13.4 场景四:`radosgw` 请求被阻塞(Blocked radosgw Requests) | 项目 | 内容 | |---|---| | **现象** | 部分(或全部)`radosgw` 请求看起来被阻塞 | | **排查手段** | 通过 `radosgw` 守护进程的 **admin socket** 查看其内部状态。默认会有一个 socket 配置在 `/var/run/ceph` 下,可用如下方式查询守护进程 | ```bash ceph daemon /var/run/ceph/client.rgw help ``` 可用命令: ```text help list available commands objecter_requests show in-progress osd requests perfcounters_dump dump perfcounters value perfcounters_schema dump perfcounters schema version get protocol version ``` **特别值得关注的是**: ```bash ceph daemon /var/run/ceph/client.rgw objecter_requests ``` 该命令会 dump 当前与 RADOS 集群之间**进行中**的请求信息,从而判断是否有请求被**无响应的 OSD** 阻塞。示例输出: ```json { "ops": [ { "tid": 1858, "pg": "2.d2041a48", "osd": 1, "last_sent": "2012-03-08 14:56:37.949872", "attempts": 1, "object_id": "fatty_25647_object1857", "object_locator": "@2", "snapid": "head", "snap_context": "0=[]", "mtime": "2012-03-08 14:56:37.949813", "osd_ops": [ "write 0~4096"]}, { "tid": 1873, "pg": "2.695e9f8e", "osd": 1, "last_sent": "2012-03-08 14:56:37.970615", "attempts": 1, "object_id": "fatty_25647_object1872", "object_locator": "@2", "snapid": "head", "snap_context": "0=[]", "mtime": "2012-03-08 14:56:37.970555", "osd_ops": [ "write 0~4096"]}], "linger_ops": [], "pool_ops": [], "pool_stat_ops": [], "statfs_ops": []} ``` **诊断方法**: 1. 在这个 dump 中有两个进行中的请求。**`last_sent` 字段是 RADOS 请求发出的时间。如果该时间已经过去很久,说明 OSD 没有响应。** 2. 例如对请求 1858,可以检查 OSD 状态: ```bash ceph pg map 2.d2041a48 ``` ```text osdmap e9 pg 2.d2041a48 (2.0) -> up [1,0] acting [1,0] ``` 3. 这告诉我们要看 **`osd.1`**——该 PG 的 primary copy: ```bash ceph daemon osd.1 ops ``` ```json { "num_ops": 651, "ops": [ { "description": "osd_op(client.4124.0:1858 fatty_25647_object1857 [write 0~4096] 2.d2041a48)", "received_at": "1331247573.344650", "age": "25.606449", "flag_point": "waiting for sub ops", "client_info": { "client": "client.4124", "tid": 1858}}, ... ``` 4. **`flag_point` 字段表明该 OSD 当前正在等待副本响应**,在本例中是 `osd.0`。 ### 13.5 场景五:Java S3 API — Peer Not Authenticated | 项目 | 内容 | |---|---| | **现象** | `[java] INFO: Unable to execute HTTP request: peer not authenticated` | | **原因** | **S3 的 Java SDK 默认使用 HTTPS**,因此要求来自**受信任证书颁发机构**的有效证书。仅测试 Ceph 对象存储服务时不需要这么严格 | | **解决方法 1** | 在 IP 或主机名前加上 `http://`。把 `conn.setEndpoint("myserver");` 改成 `conn.setEndpoint("http://myserver")` | | **解决方法 2** | 设置凭据之后,添加一个 client configuration 并把协议设为 `Protocol.HTTP`: | ```java AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); ClientConfiguration clientConfig = new ClientConfiguration(); clientConfig.setProtocol(Protocol.HTTP); AmazonS3 conn = new AmazonS3Client(credentials, clientConfig); ``` ### 13.6 场景六:405 MethodNotAllowed | 项目 | 内容 | |---|---| | **现象** | 收到 405 错误,例如 `[java] Exception in thread "main" Status Code: 405, AWS Service: Amazon S3, AWS Request ID: null, AWS Error Code: MethodNotAllowed, AWS Error Message: null, S3 Extended Request ID: null` | | **原因 1** | S3 subdomain 未正确设置。**需要**在 DNS 记录中有一条**通配(wild card)**设置,subdomain 功能才能正常工作 | | **原因 2 / 解决 2** | 确保**默认站点已被禁用**(check to ensure that the default site is disabled) | ### 13.7 场景七:`default.rgw.meta` pool 中存在大量对象 | 项目 | 内容 | |---|---| | **现象** | `default.rgw.meta` pool 中存在**大量对象** | | **原因** | 在 **jewel 之前**创建的集群**默认启用了一个元数据归档(metadata archival)特性**,使用 `default.rgw.meta` pool。该归档保存了**所有旧版本的 user 与 bucket 元数据**,导致 `default.rgw.meta` pool 中对象数量巨大 | #### 解决步骤 1:禁用 Metadata Heap(停止新增) 希望**从今往后**禁用该特性的用户,应把 `metadata_heap` 字段设为空字符串 `""`: ```bash $ radosgw-admin zone get --rgw-zone=default > zone.json # 编辑 zone.json,设置 "metadata_heap": "" $ radosgw-admin zone set --rgw-zone=default --infile=zone.json $ radosgw-admin period update --commit ``` > **效果**:这会停止把新元数据写入 `default.rgw.meta` pool,但**不会移除任何已有对象或该 pool 本身**。 #### 解决步骤 2:清理 Metadata Heap Pool(清理存量) > **前置检查(重要)**:从 **luminous** 起,radosgw 在 `default.rgw.meta` 中使用 **Pool Namespaces** 服务于**完全不同的目的**——即存储 `user_keys` 和其它**关键元数据**。因此: ```bash $ radosgw-admin zone get --rgw-zone=default | grep default.rgw.meta # 应该不匹配任何字符串(should not match any strings) ``` **在确认该 pool 没有被用于任何用途之后**,用户可以安全地删除 `default.rgw.meta` pool 中的所有对象,或可选地删除整个 pool。 > ⚠️ jewel 之前创建的集群通常只把 `default.rgw.meta` 用于元数据归档特性;但 luminous 之后该 pool 承担了新的关键用途,**务必先做上面的 grep 检查再清理**。 > 引自:[troubleshooting](https://docs.ceph.com/en/tentacle/radosgw/troubleshooting/) --- ## 十四、命令速查表(radosgw-admin 常用命令) | 分类 | 命令 | 说明 | |---|---|---| | 用户 | `radosgw-admin user create --uid= --display-name="" [--email=]` | 创建 S3 用户 | | 用户 | `radosgw-admin user info --uid=` | 查看用户信息(含配额设置) | | 用户 | `radosgw-admin user modify --uid= --display-name=""` | 修改用户信息 | | 用户 | `radosgw-admin user modify --uid= --admin` / `--admin=0` | 添加 / 移除 admin 标志 | | 用户 | `radosgw-admin user modify --uid= --placement-id=

--storage-class= --tags=` | 修改用户的 placement / storage class / tags | | 用户 | `radosgw-admin user suspend --uid=` | 暂停用户(同时禁用其 subuser) | | 用户 | `radosgw-admin user enable --uid=` | 恢复用户 | | 用户 | `radosgw-admin user rm --uid= [--purge-data] [--purge-keys]` | 删除用户及其 subuser | | 用户 | `radosgw-admin user stats --uid= [--sync-stats]` | 查看/同步用户用量与配额统计 | | 子用户 | `radosgw-admin subuser create --uid= --subuser= --access=[read\|write\|readwrite\|full]` | 创建 Swift 子用户 | | 子用户 | `radosgw-admin subuser modify --uid= --subuser= --access=full` | 修改子用户权限 | | 子用户 | `radosgw-admin subuser rm --subuser= [--purge-keys]` | 删除子用户 | | 密钥 | `radosgw-admin key create --uid= --key-type=s3 --access-key= --secret-key=` | 添加 S3 key 对 | | 密钥 | `radosgw-admin key create --subuser= --key-type=swift --secret-key=` | 添加 Swift secret key | | 密钥 | `radosgw-admin key create --subuser= --key-type=s3 --access-key= --secret-key=` | 为子用户关联 S3 key 对 | | 密钥 | `radosgw-admin key rm --uid= --key-type=s3 --access-key=` | 删除 S3 key 对 | | 密钥 | `radosgw-admin key rm --subuser= --key-type=swift` | 删除 Swift secret key | | 能力 | `radosgw-admin caps add --uid= --caps="users=*;buckets=*"` | 添加管理能力 | | 能力 | `radosgw-admin caps rm --uid= --caps="users=*"` | 移除管理能力 | | 配额 | `radosgw-admin quota set --quota-scope=user --uid= [--max-objects=N] [--max-size=S]` | 设置用户配额 | | 配额 | `radosgw-admin quota enable --quota-scope=user --uid=` | 启用用户配额 | | 配额 | `radosgw-admin quota disable --quota-scope=user --uid=` | 禁用用户配额 | | 配额 | `radosgw-admin quota set --quota-scope=bucket {--bucket=\|--uid=} [--max-objects=N] [--max-size=S]` | 设置 bucket 配额 | | 配额 | `radosgw-admin quota enable --quota-scope=bucket --uid=` | 启用 bucket 配额 | | 配额 | `radosgw-admin quota set --quota-scope=account --account-id= --max-size=10G` | 设置 account 配额 | | 配额 | `radosgw-admin quota enable --quota-scope=account --account-id=` | 启用 account 配额 | | 配额 | `radosgw-admin global quota get` | 查看全局配额 | | 配额 | `radosgw-admin global quota set --quota-scope bucket --max-objects 1024` | 设置全局配额 | | 配额 | `radosgw-admin global quota enable --quota-scope bucket` | 启用全局配额 | | 限流 | `radosgw-admin ratelimit set --ratelimit-scope=user --uid= [--max-read-ops=N] [--max-read-bytes=N] [--max-write-ops=N] [--max-write-bytes=N]` | 设置用户限流 | | 限流 | `radosgw-admin ratelimit get --ratelimit-scope=user --uid=` | 查看用户限流 | | 限流 | `radosgw-admin ratelimit enable --ratelimit-scope=user --uid=` | 启用用户限流 | | 限流 | `radosgw-admin ratelimit disable --ratelimit-scope=user --uid=` | 禁用用户限流 | | 限流 | `radosgw-admin ratelimit set --ratelimit-scope=bucket --bucket= [--max-read-ops=N] ...` | 设置 bucket 限流 | | 限流 | `radosgw-admin ratelimit get --ratelimit-scope=bucket --bucket=` | 查看 bucket 限流 | | 限流 | `radosgw-admin ratelimit enable --ratelimit-scope=bucket --bucket=` | 启用 bucket 限流 | | 限流 | `radosgw-admin ratelimit disable --ratelimit-scope=bucket --uid=` | 禁用 bucket 限流 | | 限流 | `radosgw-admin global ratelimit get` | 查看全局限流 | | 限流 | `radosgw-admin global ratelimit set --ratelimit-scope {bucket\|user\|anonymous} --max-read-ops=1024` | 设置全局限流 | | 限流 | `radosgw-admin global ratelimit enable --ratelimit-scope {bucket\|user\|anonymous}` | 启用全局限流 | | 用量 | `radosgw-admin usage show --uid= --start-date= --end-date=` | 查看用量(需 `rgw_enable_usage_log = true`) | | 用量 | `radosgw-admin usage show --show-log-entries=false` | 查看所有用户的用量汇总 | | 用量 | `radosgw-admin usage trim --uid= --end-date=` | 裁剪用量日志 | | 账号 | `radosgw-admin account create [--account-name=] [--account-id=] [--email=]` | 创建 account | | 账号 | `radosgw-admin user create --uid= --display-name= --account-id= --account-root --gen-secret --gen-access-key` | 创建 account root user | | 账号 | `radosgw-admin account rm --account-id=` | 删除 account | | 账号 | `radosgw-admin account stats --account-id= --sync-stats` | 查看 account 统计 | | 账号 | `radosgw-admin user modify --uid= --account-id=` | 把已有用户迁入 account(不可逆) | | 租户 | `radosgw-admin --tenant --uid --display-name "" user create` | 创建带显式 tenant 的用户 | | 租户 | `radosgw-admin --subuser '$:' --key-type swift --secret ` | 操作带显式 tenant 的子用户(shell 中需加引号) | | 区域 | `radosgw-admin zonegroup get` | 查看 zonegroup(含 placement_targets) | | 区域 | `radosgw-admin zone get [--rgw-zone=]` | 查看 zone(含 placement_pools) | | 区域 | `radosgw-admin zone set --rgw-zone= --infile=` | 应用 zone 配置 | | 区域 | `radosgw-admin zonegroup placement add --rgw-zonegroup --placement-id

[--storage-class ]` | 添加 placement target / storage class(zonegroup 侧) | | 区域 | `radosgw-admin zone placement add --rgw-zone --placement-id

[--storage-class ] --data-pool --index-pool --data-extra-pool [--compression ] [--placement-inline-data=false]` | 添加 placement 的 zone 侧 pool 映射 | | 区域 | `radosgw-admin zonegroup placement default --rgw-zonegroup --placement-id

` | 修改默认 placement target | | 区域 | `radosgw-admin period update --commit` | 提交 period 变更(realm 场景必做) | | Bucket | `radosgw-admin bucket stats --bucket=` | 查看 bucket 统计(含 `placement_rule`) | | 元数据 | `radosgw-admin metadata list [bucket\|bucket.instance\|user\|...]` | 列举元数据类型/条目 | | 元数据 | `radosgw-admin metadata get user:` | 获取元数据条目 | | 元数据 | `radosgw-admin metadata get bucket:` | 获取 bucket 元数据 | | 元数据 | `radosgw-admin metadata get bucket.instance::` | 获取 bucket instance 元数据 | | GC | `radosgw-admin gc list` | 查看等待 GC 的对象队列(`--include-all` 含未过期条目) | | 通知 | `radosgw-admin topic rm --topic ` | 删除通知 topic | | 配置 | `ceph config set client.rgw ` | 运行时设置 RGW 配置项 | | 配置 | `ceph config set client.rgw rgw_user_counters_cache true` | 启用 user 级 op metrics | | 配置 | `ceph config set client.rgw rgw_bucket_counters_cache true` | 启用 bucket 级 op metrics | | 配置 | `ceph config set global exporter_stats_period ` | 设置 exporter scrape 间隔 | | 诊断 | `ceph daemon /var/run/ceph/client.rgw help` | 查看 RGW admin socket 可用命令 | | 诊断 | `ceph daemon /var/run/ceph/client.rgw objecter_requests` | 查看进行中的 OSD 请求(排查阻塞) | | 诊断 | `ceph pg map ` | 查看 PG 映射到哪些 OSD | | 诊断 | `ceph daemon osd. ops` | 查看某 OSD 的进行中 op | --- ## 文档未明确项 本册以下内容在 Ceph Tentacle v20.2.4 官方文档的本册范围内**未明确说明**,未作臆测,留待后续补充或参考其它分册: 1. **各 RGW pool 的建议 PG 数量**:`pools.rst` 只说明 pool 首次被操作时由 `osd pool default pg num` / `osd pool default pgp num` 创建,并提示 `placement_pools` 中列出的 bucket index 与 data 池「需要额外调优」,但**未给出任何具体 PG 数值建议**。 2. **zone 定义中的完整 pool 清单**:`pools.rst` 明确说「The zone definitions list several more pools than that」,但本册范围内(不含 `multisite.rst`)**未逐一列出**这些 pool 的名字与用途。 3. **`realm` 与 `period` 的完整语义**:本册源文仅在 `placement.rst` 的 note 中提及 realm 与 `period update --commit`,其完整定义、层级与操作属第 10 册(`multisite.rst`)范畴。 4. **RGW 与原生 AWS S3 的完整差异清单**:官方只说明「compatible with a *large subset*」,本册源文只散落地给出 storage class 命名、`GLACIER` 前缀、bucket 命名规则、多租户、NFS 语义等具体差异点,**没有系统性清单**。 5. **RGW 的适用/不适用场景清单**:官方未提供,本册第一章中的归纳为💡补充内容。 6. **multipart 在 RADOS 中的完整布局**:`layout.rst` 未系统讲述 `shadow` 对象的切分规则、`rgw_obj_stripe_size` 与 tail 对象的关系等,只给出了零散事实点(示例对象名、`data_extra_pool` 用途、`check-objects` 检查项)。 7. **`default.rgw.log` pool 的具体用途**:`pools.rst` 与 `layout.rst` 附录只列出名字,未展开说明其存的是什么。 8. **civetweb 前端的引入版本与选项**:`frontends.rst` 只详述 `beast`;`config-ref.rst` 提到 civetweb 是「older and now non-default」,但**未说明其引入版本,也未列出其选项**。 9. **Swift with built-in authenticator 的多租户方式**:`multitenancy.rst` 原文即为 `TBD -- not in test_multen.py yet`。 10. **NFS-Ganesha idmapper 集成细节**:`nfs.rst` 原文说明「Details of idmapper integration are not provided here」。 11. **`rgw_restore_lock_max_time` 的含义**:`rgw.yaml.in` 中该配置项**没有 `desc`/`long_desc`/`fmt_desc` 字段**,只有默认值 `90`;本册按上下文推断为「restore 处理持锁的最长时间(秒)」,已标注。 12. **`rgw_nfs_namespace_expire_secs` 的语义描述**:`rgw.yaml.in` 中同样无 desc 字段;本册以 `nfs.rst` 正文(默认 300 秒 / 5 分钟)为准。 13. **Admin Ops API 中 `Get Usage` 与 `Trim Usage` 的 Special Error Responses**:源文原文即为 `TBD.` 14. **Admin Ops API 中 `Get Bucket Rate Limit` 所需 caps**:源文写的是「`users` capability set with `read` permission」,与其余限流操作的 `ratelimit=read` 不一致,**源文本身如此,未作修正**。 15. **`zone placement modify` 的独立示例**:`placement.rst` 只提到该命令支持 `--placement-inline-data=false`,未给出独立示例。 16. **`exporter_stats_period` 的 Prometheus 侧 scrape 配置**:`metrics.rst` 只给出 Prometheus 官方文档链接,未在本册展开。