CEPH-4:ceph RadowGW物件儲存功能詳解

vfanCloud發表於2022-04-01

ceph RadosGW物件儲存使用詳解

一個完整的ceph叢集,可以提供塊儲存、檔案系統和物件儲存。

本節主要介紹物件儲存RadosGw功能如何靈活的使用,叢集背景:

$ ceph -s 
  cluster:
    id:     f0a8789e-6d53-44fa-b76d-efa79bbebbcf
    health: HEALTH_OK
 
  services:
    mon: 1 daemons, quorum a (age 2d)
    mgr: a(active, since 2d)
    mds: cephfs:1 {0=cephfs-a=up:active} 1 up:standby-replay
    osd: 1 osds: 1 up (since 2d), 1 in (since 2d)
    rgw: 1 daemon active (my.store.a)
 
  data:
    pools:   10 pools, 200 pgs
    objects: 1.29k objects, 3.5 GiB
    usage:   60 GiB used, 798 GiB / 858 GiB avail
    pgs:     200 active+clean
 
  io:
    client:   852 B/s rd, 1 op/s rd, 0 op/s wr

什麼是物件儲存

  1. 物件儲存,又稱鍵值儲存,通過其介面指令,例如簡單的GET、PUT、DEL等,向儲存服務上傳下載資料;
  2. 物件儲存中所有資料都被認為是一個物件。所以,任何資料都可以存入物件儲存中,如圖片、視訊、音訊等;
  3. 常見的物件儲存廠商有Swift、S3等,ceph就支援Swift API和AWS S3兩種標準。

ceph物件儲存的構成

Ceph物件儲存是通過 RGW元件 來實現,什麼是 rgw 呢?

  1. rgw全稱Rados Gateway,是一種服務,使客戶端能夠利用標準物件儲存API來訪問ceph物件閘道器;
  2. ceph 0.8版本之後使用Civeweb的web伺服器來響應api請求,說白了,rgw裡邊就是一個web服務;
  3. 客戶端使用http/https協議通過RESTful API與rgw通訊;
  4. rgw通過librados與ceph叢集通訊,利用cephx加密協議與ceph儲存通訊;
  5. rgw通過bucket來實現資料儲存和多使用者的隔離;
  6. 可以部署多個rgw,實現負載均衡及高可用。

ceph RadosGW中有一個bucket桶的概念,一般專案或者分類會使用bucket來進行隔離,bucket的許可權控制,想要操作某個bucket,操作使用者必須有對此bucket的對應操作許可權,bucket最終的資料其實還是通過PG來落盤到後端的osd儲存中的。

RadosGW儲存池作用

rgw安裝流程請參考之前的部署文件,此處不在贅述,預設埠7480,能夠curl通就表示安裝成功:

$ curl 10.153.204.13:30080
<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>anonymous</ID><DisplayName></DisplayName></Owner><Buckets></Buckets></ListAllMyBucketsResult>

我這裡更改了預設埠,改為了30080

rgw安裝完畢後,會有一些預設建立的儲存池:

$ ceph osd lspools | grep rgw 
1 .rgw.root
3 my-store.rgw.control
6 my-store.rgw.meta
7 my-store.rgw.log
8 my-store.rgw.buckets.index
9 my-store.rgw.buckets.non-ec
10 my-store.rgw.buckets.data

這些儲存池也是分為兩種型別的,一種是後設資料儲存池,一種是資料儲存池:

  • .rgw.root : 包含realm(領域資訊),比如zone和zonegroup。
  • rgw.log:儲存日誌資訊,使用者記錄各種log資訊。
  • rgw.control:系統控制池,在有資料更新時,通知其它RGW更新快取。
  • rgw.meta:後設資料儲存池,通過不同的名稱空間分別儲存不同的rados物件,這些名稱空間包括使用者的UID,及其Bucket對映資訊的名稱空間users.uid,使用者的金鑰名稱空間users.keys,使用者的emai名稱空間users.email,使用者的subuser的名稱空間 users.swift,bucket的名稱空間root等。
  • rgw.buckets.index:存放bucket到object的索引資訊。
  • rgw.buckets.non-ec:資料的額外資訊儲存池。
  • rgw.buckets.data:存放物件的資料

RadosGW常用操作詳解

檢視全部zone

$ radosgw-admin zone list 
{
    "default_info": "a06a6df5-68a4-47f0-9afa-2ac1c09aee58",
    "zones": [
        "my-store"
    ]
}

預設為default,我這裡更改名字叫my-store

檢視zone詳情

$ radosgw-admin zone get --rgw-zone=my-store
{
    "id": "a06a6df5-68a4-47f0-9afa-2ac1c09aee58",
    "name": "my-store",
    "domain_root": "my-store.rgw.meta:root",
    "control_pool": "my-store.rgw.control",
    "gc_pool": "my-store.rgw.log:gc",
    "lc_pool": "my-store.rgw.log:lc",
    "log_pool": "my-store.rgw.log",
    "intent_log_pool": "my-store.rgw.log:intent",
    "usage_log_pool": "my-store.rgw.log:usage",
    "roles_pool": "my-store.rgw.meta:roles",
    "reshard_pool": "my-store.rgw.log:reshard",
    "user_keys_pool": "my-store.rgw.meta:users.keys",
    "user_email_pool": "my-store.rgw.meta:users.email",
    "user_swift_pool": "my-store.rgw.meta:users.swift",
    "user_uid_pool": "my-store.rgw.meta:users.uid",
    "otp_pool": "my-store.rgw.otp",
    "system_key": {
        "access_key": "",
        "secret_key": ""
    },
    "placement_pools": [
        {
            "key": "default-placement",
            "val": {
                "index_pool": "my-store.rgw.buckets.index",
                "storage_classes": {
                    "STANDARD": {
                        "data_pool": "my-store.rgw.buckets.data"
                    }
                },
                "data_extra_pool": "my-store.rgw.buckets.non-ec",
                "index_type": 0
            }
        }
    ],
    "realm_id": ""
}

radosgw建立新使用者認證

$ radosgw-admin user create --uid="vfan" --display-name="my vfan"{
    "user_id": "vfan",
    "display_name": "my vfan",
    "email": "",
    "suspended": 0,
    "max_buckets": 1000,
    "subusers": [],
    "keys": [
        {
            "user": "vfan",
            "access_key": "Q6VGP3LYMH99D0A9GUV0",
            "secret_key": "NVDfq7CBJgpUnCXKqbgVuKvI3siWNbx0sRltClA4"
        }
    ],
    "swift_keys": [],
    "caps": [],
    "op_mask": "read, write, delete",
    "default_placement": "",
    "default_storage_class": "",
    "placement_tags": [],
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "user_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "temp_url_keys": [],
    "type": "rgw",
    "mfa_ids": []
}

新建一個子使用者

為了給使用者新建一個子使用者 (Swift 介面) ,必須為該子使用者指定使用者的 ID(--uid={username}),子使用者的 ID 以及訪問級別:

$ radosgw-admin subuser create --uid=vfan --subuser=vfan:swift --access=full
{
    "user_id": "vfan",
    "display_name": "my vfan",
    "email": "",
    "suspended": 0,
    "max_buckets": 1000,
    "subusers": [
        {
            "id": "vfan:swift",
            "permissions": "full-control"
        }
    ],
    "keys": [
        {
            "user": "vfan",
            "access_key": "Q6VGP3LYMH99D0A9GUV0",
            "secret_key": "NVDfq7CBJgpUnCXKqbgVuKvI3siWNbx0sRltClA4"
        }
    ],
    "swift_keys": [
        {
            "user": "vfan:swift",
            "secret_key": "GrjjD8yJgr2khUCIeRmggNMWqnganFlhMKMMom9s"
        }
    ],
    "caps": [],
    "op_mask": "read, write, delete",
}

--access=full並不僅僅代表讀寫,因為他還包括訪問許可權策略。

檢視user列表

$ radosgw-admin user list 
[
    "vfan",
    "ceph-object-user"
]

禁用或啟動一個使用者

建立賬戶後,預設是啟用狀態,可以將其設定為關閉狀態:

## 停用一個使用者
$ radosgw-admin user suspend --uid=vfan

## 啟用一個使用者
$ radosgw-admin user enable --uid=vfan

主要是使用者中的"suspended"值發生了變化,開啟為0,關閉為1。

新增或刪除 使用者管理許可權

## 新增
$ radosgw-admin caps add --uid=vfan --caps="users=*"

## 刪除
$ radosgw-admin caps rm --uid=vfan --caps="users=write"

--caps="[users|buckets|metadata|usage|zone]=[*|read|write|read, write]"

刪除使用者 或 子使用者

## 刪除使用者
$ radosgw-admin user rm --uid=vfan

## 刪除子使用者
$ radosgw-admin subuser rm --subuser=vfan:swift

檢視所有的bucket桶

$ radosgw-admin bucket list 
[
    "my-test-bucket"
]

檢視桶內物件

$ radosgw-admin bucket list --bucket=my-test-bucket
[
    {
        "name": "hello.txt",
        "instance": "",
        "ver": {
            "pool": 10,
            "epoch": 1
        },
        "locator": "",
        "exists": "true",
        "meta": {
            "category": 1,
            "size": 12,
            "mtime": "2022-03-30T10:51:38.420295Z",
            "etag": "ed076287532e86365e841e92bfc50d8c",
            "storage_class": "",
            "owner": "vfan",
            "owner_display_name": "my vfan",
            "content_type": "application/octet-stream",
            "accounted_size": 12,
            "user_data": "",
            "appendable": "false"
        },
        "tag": "a06a6df5-68a4-47f0-9afa-2ac1c09aee58.24132.17942",
        "flags": 0,
        "pending_map": [],
        "versioned_epoch": 0
    }
]

檢視儲存桶詳情

$ radosgw-admin bucket stats --bucket=my-test-bucket
{
    "bucket": "my-test-bucket",
    "num_shards": 0,
    "tenant": "",
    "zonegroup": "fd710024-4ba3-41bb-9f96-579d8f03dd1b",
    "placement_rule": "default-placement",
    "explicit_placement": {
        "data_pool": "",
        "data_extra_pool": "",
        "index_pool": ""
    },
    "id": "a06a6df5-68a4-47f0-9afa-2ac1c09aee58.24134.1",
    "marker": "a06a6df5-68a4-47f0-9afa-2ac1c09aee58.24134.1",
    "index_type": "Normal",
    "owner": "vfan",
    "ver": "0#2",
    "master_ver": "0#0",
    "mtime": "2022-03-30T10:51:38.323147Z",
    "creation_time": "2022-03-30T10:51:38.321498Z",
    "max_marker": "0#",
    "usage": {
        "rgw.main": {
            "size": 12,
            "size_actual": 4096,
            "size_utilized": 12,
            "size_kb": 1,
            "size_kb_actual": 4,
            "size_kb_utilized": 1,
            "num_objects": 1
        }
    },
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    }
}

檢視使用者配額

$ radosgw-admin user info --uid=vfan | grep -A 5 "quota"
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
--
    "user_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1

預設這些配額都是未啟用的,處於false狀態。

啟用使用者配額

$ radosgw-admin quota enable --quota-scope=user --uid=vfan

$ radosgw-admin user info --uid=vfan | grep -A 5 "quota"
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
--
    "user_quota": {
        "enabled": true,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1

已啟用使用者配額,此時可以修改最大限額,預設是不限制。

更新配額

$ radosgw-admin quota set --uid=vfan --quota-scope=user --max-objects=10000 --max-size=107374182400
[cephadmin@yq01-aip-aikefu10.yq01.baidu.com ~]$ radosgw-admin user info --uid=vfan | grep -A 5 "quota"    
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
--
    "user_quota": {
        "enabled": true,
        "check_on_raw": false,
        "max_size": 107374182400,
        "max_size_kb": 104857600,
        "max_objects": 10000

max_size單位是bytes,max_size_kb單位是kb。

操縱radosgw

一般物件儲存都由開發在程式碼層面控制,幾乎不需要我們運維人員操作什麼,只需要把使用者許可權和叢集維護好就沒啥問題了,接下來用一段python程式碼來演示其bucket以及增刪檔案的操作。也有一些命令可以實現,例如s3cmd等。

需要先安裝好python3環境,以及python的boto模組

# pip3 install boto-2.41.0-py2.py3-none-any.whl

如果沒有pip源,離線下載地址:https://pypi.org/simple/boto/

python指令碼編寫

這裡測試使用上邊演示新建立的使用者vfan

vi ceph-s3.py

import boto.s3.connection

access_key = 'Q6VGP3LYMH99D0A9GUV0' #建立S3使用者時返回的AK
secret_key = 'NVDfq7CBJgpUnCXKqbgVuKvI3siWNbx0sRltClA4' #S3使用者的SK
host = '10.153.204.13' # RWG節點IP和埠
port = 30080
# 新建一個連線
conn = boto.connect_s3(
        aws_access_key_id=access_key,
        aws_secret_access_key=secret_key,
        host=host, port=port,
        is_secure=False, calling_format=boto.s3.connection.OrdinaryCallingFormat(),
       )
# 新建一個Bucket
bucket = conn.create_bucket('my-vfan-bucket')

# 列出使用者的所有Bucket
for bucket in conn.get_all_buckets():
    print("桶名稱: %s, 建立時間: %s" %(bucket.name,bucket.creation_date))

# 列出Bucket內容
for key in bucket.list():
    print("key名稱: %s, 檔案大小: %s, 修改時間: %s" %(key.name,key.size,key.last_modified))

# 新建一個物件
key = bucket.new_key('hi.txt')
key.set_contents_from_string('Hello World!')

# 下載一個物件到檔案
key = bucket.get_key('hi.txt')
key.get_contents_to_filename('/tmp/hi.txt')

執行py指令碼

# python3 ceph-s3.py
桶名稱: my-test-bucket, 建立時間: 2022-03-30T10:51:38.321Z
桶名稱: my-vfan-bucket, 建立時間: 2022-04-01T07:32:54.671Z

# cat /tmp/hi.txt 
Hello World!

已經新建立了一個名為my-vfan-bucket的bucket,並新建了一個物件hi.txt,並下載到了本地的/tmp目錄下。

可以優化一下指令碼,使其可以單項操作

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
@Time    : 2021-12-22 19:14
@Author  : xxxxxx
@Email   : xxxxxx
@File    : bucket.py
@Software: PyCharm
"""
import boto
import boto.s3.connection


class Bucket():
    """
    ceph中bucket相關的類
    boto s3 api手冊:http://boto.readthedocs.org/en/latest/ref/s3.html
    boto s3 api用法:https://docs.ceph.com/en/latest/radosgw/s3/python/#
    """
    def __init__(self, ak, sk, host, port):
        self.ak = ak
        self.sk = sk
        self.host = host
        self.port = port
        self.conn = boto.connect_s3(aws_access_key_id=self.ak, aws_secret_access_key=self.sk, host=self.host,
                                    port=self.port, is_secure=False,
                                    calling_format=boto.s3.connection.OrdinaryCallingFormat())
        print self.conn

    def bucketList(self):
        """
        獲取所有的bucketList
        :return:
        """
        for bucket in self.conn.get_all_buckets():
            print("{name}\t{created}".format(name=bucket.name, created=bucket.creation_date))

    def bucketCreate(self, bucketName):
        """
        建立bucket
        :return:
        """
        createRes = self.conn.create_bucket(bucketName)
        print createRes

    def bucketDelete(self):
        """
        刪除bucket
        :return:
        """
        pass

if __name__ == "__main__":
    """
    主函式
    """
    access_key = "FHPC3HED7P7J8ADFQVOD"
    secret_key = "Zgf01sjynnAbNS6yCO99VFphDQ6sOlmPBRRd7P2E"
    host = "xxxxx"
    port = 8000
    bucketName = 'share'
    bucket = Bucket(access_key, secret_key, host, port)
    # 建立bucket
    bucket.bucketCreate(bucketName)
    # 檢視bucket列表
    # bucket.bucketList()

可以再基於此指令碼優化,增加其他功能。

RadosGW相關操作至此已演示介紹完畢,後續會陸續介紹一些自定義crush規則、pg及一些常用的引數配置。

相關文章