Files
wiki/存储/Ceph/知识库/09-RGW-核心与运维篇.md
T
2026-09-18 13:49:11 +08:00

3406 lines
180 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> 基于 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 对象,名字为 `<user_id>`,位于 pool `default.rgw.meta` 的 `users.uid` namespace |
| bucket(名字→实例的映射) | pool `default.rgw.meta` 的 `root` namespace |
| bucket index | 默认每个 bucket 一个 RADOS 对象 `.dir.<marker>`,位于 `default.rgw.buckets.index`;omap 存 key-value 映射 |
| object data | 一个或多个 RADOS 对象,位于 `default.rgw.buckets.data`,对象名 `<marker>_<key>` |
| 用户的 bucket 列表 | 对象 `<user_id>.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:<bucket>
radosgw-admin metadata get bucket.instance:<bucket>:<bucket_id>
radosgw-admin metadata get user:<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, 对象名 <user_id>
2) bucket 记录 → pool default.rgw.meta, namespace root
(读取该记录以获得所谓 marker,marker 充当 bucket ID)
3) 对象数据 → pool default.rgw.buckets.data
RADOS 对象名 = <marker>_<key>
例: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 列表 | 对象 `<user_id>.buckets`(例如 `foo.buckets`)的 **omap**,位于 pool `default.rgw.meta`、namespace `users.uid`。在列举 bucket、更新 bucket 内容、更新与获取 bucket 统计(如 quota)时访问这些对象 |
| 某 bucket 中的对象列表 | 走 **bucket index**(见 3.3);index 对象默认命名 `.dir.<marker>`,位于 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.
<zone>.rgw.control
notify.<N>
<zone>.rgw.meta
Multiple namespaces with different kinds of metadata:
namespace: root
<bucket>
.bucket.meta.<bucket>:<marker> # 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 "<user>" objects
and per-user lists of buckets in omaps of "<user>.buckets" objects.
The "<user>" 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
<zone>.rgw.buckets.index
Objects are named .dir.<marker>: each contains a bucket index.
If the index is sharded, each shard appends the shard index after
the marker.
<zone>.rgw.buckets.data
example: default.7593.4__shadow_.488urDFerTYXavx4yAd-Op8mxehnvTI_1
<marker>_<key>
```
**marker 格式**(源文原文):marker 示例为 `default.16004.1` 或 `default.7593.4`。当前格式为 `<zone>.<instance_id>.<bucket_id>`。但 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.<N>`),用于跨 RGW 通信 | 文档未明确 |
| `default.rgw.meta` | 多 namespace 元数据池,含 `root` / `users.uid` / `users.email` / `users.keys` / `users.swift` | 文档未明确 |
| `default.rgw.log` | 日志(源文仅列出名字,未展开用途) | 文档未明确 |
| `default.rgw.buckets.index` | **bucket index**。对象命名 `.dir.<marker>`;分片时追加 shard index。**必须**是副本池(不能 EC),且应放在快速 SSD OSD 上(`layout.rst` 明示) | 文档未明确;源文提示该池「需要额外调优」 |
| `default.rgw.buckets.data` | **对象数据**。对象命名 `<marker>_<key>`。可以是 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 个 `<zone>.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 <user-id> \
--placement-id <default-placement-id> \
--storage-class <default-storage-class> \
--tags <tag1,tag2>
```
#### 4.5.3 S3 Bucket Placement
用 S3 协议创建 bucket 时,可通过 **LocationConstraint** 提供 placement target,覆盖用户与 zonegroup 的默认值。
- 常规情况下 LocationConstraint 必须匹配 zonegroup 的 `api_name`:
```xml
<LocationConstraint>default</LocationConstraint>
```
- 在 `api_name` 后加冒号即可指定自定义 placement target:
```xml
<LocationConstraint>default:new-placement</LocationConstraint>
```
#### 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=<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=<type>` | 指定 key 类型,可选 `s3`、`swift` |
| `--access-key=<key>` | 手动指定 S3 access key |
| `--secret-key=<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=<uid>` |
| `quota disable`(user 级) | 禁用已启用的用户配额 | `--quota-scope=user`、`--uid` | `radosgw-admin quota disable --quota-scope=user --uid=<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=<uid>` |
| `quota disable`(bucket 级) | 禁用 bucket 配额 | `--quota-scope=bucket`、`--uid` | `radosgw-admin quota disable --quota-scope=bucket --uid=<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=<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=<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=<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>`、`bucket.instance:<bucket>:<bucket_id>`、`user:<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&quota-type=user` | `users=read` / `users=write` |
| 26 | Get/Set Bucket Quota(user 下) | `GET` / `PUT` | `/{admin}/user?quota&quota-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&quota-type=account` | `accounts=write` |
| 29 | Set Bucket Quota under an Account | `PUT` | `/{admin}/account?quota&quota-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=<uid>&quota-type=user` | 需要 `users=read` |
| Set User Quota | `PUT /admin/user?quota&uid=<uid>&quota-type=user` | 需要 `users=write`。**请求体内容必须包含对应读操作所编码的配额设置的 JSON 表示** |
| Get Bucket Quota | `GET /admin/user?quota&uid=<uid>&quota-type=bucket` | 需要 `users=read` |
| Set Bucket Quota | `PUT /admin/user?quota&uid=<uid>&quota-type=bucket` | 需要 `users=write`。请求体同上 |
| Set Quota for an Individual Bucket | `PUT /admin/bucket?quota&uid=<uid>&bucket=<bucket-name>` | 需要 `buckets=write`。请求体同上 |
| Set Account Quota | `PUT /admin/account?quota&id=<account_id>&quota-type=account` | 需要 `accounts=write` |
| Set Bucket Quota under an Account | `PUT /admin/account?quota&id=<account_id>&quota-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=<uid>` | `ratelimit=read` |
| Set User Rate Limit | `POST /{admin}/ratelimit?ratelimit-scope=user&uid=<uid><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>][enabled=<True\|False>]>` | `ratelimit=write` |
| Get Bucket Rate Limit | `GET /{admin}/ratelimit?bucket=<bucket>&ratelimit-scope=bucket` | `users=read`(源文如此表述) |
| Set Rate Limit for an Individual Bucket | `POST /{admin}/ratelimit?bucket=<bucket-name>&ratelimit-scope=bucket<[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>]>` | `ratelimit=write` |
| Get Global Rate Limit | `GET /{admin}/ratelimit?global=<True\|False>` | `ratelimit=read` |
| Set Global User Rate Limit | `POST /{admin}/ratelimit?ratelimit-scope=user&global=<True\|False><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>][enabled=<True\|False>]>` | `ratelimit=write` |
| Set Global Rate Limit Bucket | `POST /{admin}/ratelimit?ratelimit-scope=bucket&global=<True\|False><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>]>` | `ratelimit=write` |
| Set Global Anonymous User Rate Limit | `POST /{admin}/ratelimit?ratelimit-scope=anon&global=<True\|False><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>][enabled=<True\|False>]>` | `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` 选项 | 额外的命令行选项 |
| `'<tenant>$<user>'` 语法 | 在 `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://<host>:<port>/foo/bar?AWSAccessKeyId=b200fb6634c547199e436a0f93c0c46e&Expires=1542890806&Signature=eok6CYQC%2FDwmQQmqvY5jTg6ehXU%3D
http://<host>:<port>/7188e165c0ae4424ac68ae2e89a05c50:foo/bar?AWSAccessKeyId=b200fb6634c547199e436a0f93c0c46e&Expires=1542890806&Signature=eok6CYQC%2FDwmQQmqvY5jTg6ehXU%3D
```
取决于签名生成时是否传入了 tenant 前缀。
- public read ACL(同上对象)——**必须**带前缀:
```text
http://<host>:<port>/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 创建一个名为 **`<tenant_id>$<tenant_id`** 的用户,`<tenant_id>` 是 Keystone tenant(project)UUID,例如 `7188e165c0ae4424ac68ae2e89a05c50$7188e165c0ae4424ac68ae2e89a05c50`。
- 该用户创建 Swift container 时,radosgw 内部把给定的 container 名翻译为 **`<tenant_id>/<container_name>`**,例如 `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 物化:文件为 `<name>`,目录为 `<name>/` |
| 非叶目录 | (如上例的 `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 <ganesha-host-name>:/ <mount-point>
```
```text
# /etc/fstab
<ganesha-host-name>:/ <mount-point> nfs noauto,soft,nfsvers=4.1,sync,proto=tcp 0 0
```
#### NFSv3 客户端
Linux 客户端可通过提供 `nfsvers=3` 与 `noacl` 挂载选项以 NFSv3 挂载。要使用 UDP 作为传输,加入 `proto=udp`;但**首选 TCP**:
```text
<ganesha-host-name>:/ <mount-point> 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=<uid> --display-name="<name>" [--email=<e>]` | 创建 S3 用户 |
| 用户 | `radosgw-admin user info --uid=<uid>` | 查看用户信息(含配额设置) |
| 用户 | `radosgw-admin user modify --uid=<uid> --display-name="<name>"` | 修改用户信息 |
| 用户 | `radosgw-admin user modify --uid=<uid> --admin` / `--admin=0` | 添加 / 移除 admin 标志 |
| 用户 | `radosgw-admin user modify --uid=<uid> --placement-id=<p> --storage-class=<s> --tags=<t1,t2>` | 修改用户的 placement / storage class / tags |
| 用户 | `radosgw-admin user suspend --uid=<uid>` | 暂停用户(同时禁用其 subuser) |
| 用户 | `radosgw-admin user enable --uid=<uid>` | 恢复用户 |
| 用户 | `radosgw-admin user rm --uid=<uid> [--purge-data] [--purge-keys]` | 删除用户及其 subuser |
| 用户 | `radosgw-admin user stats --uid=<uid> [--sync-stats]` | 查看/同步用户用量与配额统计 |
| 子用户 | `radosgw-admin subuser create --uid=<uid> --subuser=<uid:sub> --access=[read\|write\|readwrite\|full]` | 创建 Swift 子用户 |
| 子用户 | `radosgw-admin subuser modify --uid=<uid> --subuser=<uid:sub> --access=full` | 修改子用户权限 |
| 子用户 | `radosgw-admin subuser rm --subuser=<uid:sub> [--purge-keys]` | 删除子用户 |
| 密钥 | `radosgw-admin key create --uid=<uid> --key-type=s3 --access-key=<ak> --secret-key=<sk>` | 添加 S3 key 对 |
| 密钥 | `radosgw-admin key create --subuser=<uid:sub> --key-type=swift --secret-key=<sk>` | 添加 Swift secret key |
| 密钥 | `radosgw-admin key create --subuser=<uid:sub> --key-type=s3 --access-key=<ak> --secret-key=<sk>` | 为子用户关联 S3 key 对 |
| 密钥 | `radosgw-admin key rm --uid=<uid> --key-type=s3 --access-key=<ak>` | 删除 S3 key 对 |
| 密钥 | `radosgw-admin key rm --subuser=<uid:sub> --key-type=swift` | 删除 Swift secret key |
| 能力 | `radosgw-admin caps add --uid=<uid> --caps="users=*;buckets=*"` | 添加管理能力 |
| 能力 | `radosgw-admin caps rm --uid=<uid> --caps="users=*"` | 移除管理能力 |
| 配额 | `radosgw-admin quota set --quota-scope=user --uid=<uid> [--max-objects=N] [--max-size=S]` | 设置用户配额 |
| 配额 | `radosgw-admin quota enable --quota-scope=user --uid=<uid>` | 启用用户配额 |
| 配额 | `radosgw-admin quota disable --quota-scope=user --uid=<uid>` | 禁用用户配额 |
| 配额 | `radosgw-admin quota set --quota-scope=bucket {--bucket=<b>\|--uid=<uid>} [--max-objects=N] [--max-size=S]` | 设置 bucket 配额 |
| 配额 | `radosgw-admin quota enable --quota-scope=bucket --uid=<uid>` | 启用 bucket 配额 |
| 配额 | `radosgw-admin quota set --quota-scope=account --account-id=<id> --max-size=10G` | 设置 account 配额 |
| 配额 | `radosgw-admin quota enable --quota-scope=account --account-id=<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=<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=<uid>` | 查看用户限流 |
| 限流 | `radosgw-admin ratelimit enable --ratelimit-scope=user --uid=<uid>` | 启用用户限流 |
| 限流 | `radosgw-admin ratelimit disable --ratelimit-scope=user --uid=<uid>` | 禁用用户限流 |
| 限流 | `radosgw-admin ratelimit set --ratelimit-scope=bucket --bucket=<b> [--max-read-ops=N] ...` | 设置 bucket 限流 |
| 限流 | `radosgw-admin ratelimit get --ratelimit-scope=bucket --bucket=<b>` | 查看 bucket 限流 |
| 限流 | `radosgw-admin ratelimit enable --ratelimit-scope=bucket --bucket=<b>` | 启用 bucket 限流 |
| 限流 | `radosgw-admin ratelimit disable --ratelimit-scope=bucket --uid=<b>` | 禁用 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=<uid> --start-date=<d> --end-date=<d>` | 查看用量(需 `rgw_enable_usage_log = true`) |
| 用量 | `radosgw-admin usage show --show-log-entries=false` | 查看所有用户的用量汇总 |
| 用量 | `radosgw-admin usage trim --uid=<uid> --end-date=<d>` | 裁剪用量日志 |
| 账号 | `radosgw-admin account create [--account-name=<n>] [--account-id=<id>] [--email=<e>]` | 创建 account |
| 账号 | `radosgw-admin user create --uid=<u> --display-name=<n> --account-id=<id> --account-root --gen-secret --gen-access-key` | 创建 account root user |
| 账号 | `radosgw-admin account rm --account-id=<id>` | 删除 account |
| 账号 | `radosgw-admin account stats --account-id=<id> --sync-stats` | 查看 account 统计 |
| 账号 | `radosgw-admin user modify --uid=<u> --account-id=<id>` | 把已有用户迁入 account(不可逆) |
| 租户 | `radosgw-admin --tenant <t> --uid <u> --display-name "<n>" user create` | 创建带显式 tenant 的用户 |
| 租户 | `radosgw-admin --subuser '<tenant>$<user>:<sub>' --key-type swift --secret <s>` | 操作带显式 tenant 的子用户(shell 中需加引号) |
| 区域 | `radosgw-admin zonegroup get` | 查看 zonegroup(含 placement_targets) |
| 区域 | `radosgw-admin zone get [--rgw-zone=<z>]` | 查看 zone(含 placement_pools) |
| 区域 | `radosgw-admin zone set --rgw-zone=<z> --infile=<f>` | 应用 zone 配置 |
| 区域 | `radosgw-admin zonegroup placement add --rgw-zonegroup <zg> --placement-id <p> [--storage-class <sc>]` | 添加 placement target / storage class(zonegroup 侧) |
| 区域 | `radosgw-admin zone placement add --rgw-zone <z> --placement-id <p> [--storage-class <sc>] --data-pool <dp> --index-pool <ip> --data-extra-pool <xp> [--compression <c>] [--placement-inline-data=false]` | 添加 placement 的 zone 侧 pool 映射 |
| 区域 | `radosgw-admin zonegroup placement default --rgw-zonegroup <zg> --placement-id <p>` | 修改默认 placement target |
| 区域 | `radosgw-admin period update --commit` | 提交 period 变更(realm 场景必做) |
| Bucket | `radosgw-admin bucket stats --bucket=<b>` | 查看 bucket 统计(含 `placement_rule`) |
| 元数据 | `radosgw-admin metadata list [bucket\|bucket.instance\|user\|...]` | 列举元数据类型/条目 |
| 元数据 | `radosgw-admin metadata get user:<user>` | 获取元数据条目 |
| 元数据 | `radosgw-admin metadata get bucket:<bucket>` | 获取 bucket 元数据 |
| 元数据 | `radosgw-admin metadata get bucket.instance:<bucket>:<bucket_id>` | 获取 bucket instance 元数据 |
| GC | `radosgw-admin gc list` | 查看等待 GC 的对象队列(`--include-all` 含未过期条目) |
| 通知 | `radosgw-admin topic rm --topic <name>` | 删除通知 topic |
| 配置 | `ceph config set client.rgw <CONFIG_VARIABLE> <VALUE>` | 运行时设置 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 <seconds>` | 设置 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 <pgid>` | 查看 PG 映射到哪些 OSD |
| 诊断 | `ceph daemon osd.<N> 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 官方文档链接,未在本册展开。