注意:
- 此教程需要访问 Oracle Cloud。要注册免费账户,请参阅开始使用 Oracle Cloud Infrastructure Free Tier 。
- 它使用 Oracle Cloud Infrastructure 身份证明、租户和区间示例值。完成实验室时,请将这些值替换为特定于您的云环境的值。
使用 Oracle Cloud Infrastructure Object Storage Service 和 OpenStack Swift API
简介
Oracle Cloud Infrastructure (OCI) 对象存储是一种数据存储架构,它以对象形式管理和组织数字信息,每个对象由数据、元数据和唯一标识符组成。与传统的文件或块存储不同,OCI 对象存储不依赖于分层结构,因此可以高效、可扩展地处理大量非结构化数据。对象存储在平面地址空间中,简化了数据检索并实现了无缝的可扩展性。该解决方案非常适合各种数据类型,例如多媒体内容和备份,使其成为云环境、归档存储和分布式系统的强大选择,因为它具有灵活性、耐用性和易于访问。用户通过 HTTP 协议使用 REST 接口与对象存储服务进行交互。
OCI 对象存储服务是一个基于云的存储解决方案,Oracle 可处理管理复杂性,确保可靠且经济高效的数据持久性。平台弹性允许从无缝扩展的能力逐步开始,所有这些都不会影响性能或服务可靠性。
OCI 对象存储通过 Amazon S3 兼容 API 提供了与 OpenStack Swift API 和 Amazon 简单存储服务 (Amazon S3) 的 API 兼容。这样,客户可以继续使用现有工具(例如 SDK 客户端),从而尽可能减少对应用进行更改的需求。有关详细信息,请参阅 Amazon S3 兼容 API 。本教程将重点介绍 OCI OpenStack Swift 兼容 API 使用情况。
在开始讨论 OpenStack Swift API 之前,我们需要澄清 OCI 对象存储中使用的一些构造。
-
名称空间用于在 OCI 区域级别为存储桶和对象提供账户级别隔离。创建 Oracle Cloud Infrastructure 租户账户后,将分配唯一且不可变的 OCI Object Storage 名称空间名称。这些名称空间可以扩展到租户内的所有区间,并且在所有区域中保持不变。
-
存储桶是用于存储对象的逻辑容器。存储桶是区域级资源。
-
对象:任何类型的数据(无论内容类型如何)都存储为对象。对象包含对象本身和有关对象的元数据。每个对象都存储在桶中。
-
区间是用于组织云资源的逻辑构造。OCI 对象存储桶只能存在于一个区间中。用于控制对对象存储资源的访问的 Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) 策略按区间应用。
OpenStack Swift 定义了三个结构:Account、Container 和 Object。
-
帐户表示层次的顶层,与项目或租户同义。
-
容器用作 objects 的名称空间。
现在,我们可以确定 OCI 对象存储与 OpenStack Swift API 之间的等效资源。
- OCI 对象存储名称空间等效于 Swift account 。
- OCI 对象存储桶等效于 Swift 容器。
- OCI 对象存储对象等效于 Swift 对象。
目标
- 说明使用 OCI 对象存储服务与 OpenStack Swift 兼容 API 的各种方式。
先决条件
-
生成 OCI 验证令牌: OCI Swift API 的使用需要使用 OCI 验证令牌进行验证。有关更多信息,请参见 Creating an Auth Token 。
-
创建策略来授予用户使用 OCI 对象存储服务的访问权限。Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) 策略,允许用户访问以管理区间中的对象系列资源。OCI 资源按区间组织,对资源的访问由为区间定义的策略控制。对于本教程,您需要创建以下策略。
allow group <group-name> to manage object-family in tenancy
.
使用 OCI Swift API
OCI Swift API 区域端点使用一致的 URL 格式 https://swiftobjectstorage.<region-identifier>.oraclecloud.com
。例如,美国东部区域 (US-ashburn-1) 中的原生 OCI Swift API 端点为 https://swiftobjectstorage.US-ashburn-1.oraclecloud.com
。
考虑到区域级别的租户级别隔离,OCI Swift API 端点变为:https://swiftobjectstorage.<region-identifier>.oraclecloud.com/<tenancy-namespace>
,其中 <tenancy-namespace>
是要创建资料档案库的租户的自动生成的对象存储名称空间字符串。有关详细信息,请参阅“租户信息”页。
OCI Swift API 缺乏区间的概念。默认情况下,使用 OCI Amazon S3 兼容 API 或 OCI Swift API 创建的存储桶是在 Oracle Cloud Infrastructure 租户的根区间中创建的。您可以为 OCI Amazon S3 兼容 API 或 OCI Swift API 指定其他区间来创建存储桶。有关详细信息,请参阅编辑租户的 Amazon S3 兼容 API 和 Swift API 区间指定。
OCI Swift API 支持三种验证请求的方法。
方法 1:使用基本授权标头
用户名的格式为 <username>
。例如,john.doe@acme.com
。如果您的租户与 Oracle Identity Cloud Service 联合,请使用 oracleidentitycloudservice/<username>
格式。
密码是为用户生成的验证令牌。例如,my-auth-token
。有关详细信息,请参阅获取验证令牌。
对 OCI Swift API 的每个请求都应包含以下标头。
- 授权:
Basic <base64(username:password)>
。
例如,如果 username 为 oracleidentitycloudservice/john.doe@acme.com
,password 为 my-auth-token
,则标头将如下所示:
- 授权:
Basic b3JhY2xlaWRlbnRpdHljbG91ZHNlcnZpY2Uvam9obi5kb2VAYWNtZS5jb206b ktYXV0aC10b2tlbg==
。
我们将使用官方文档中介绍的一些 API 调用,请参阅 OpenStack Swift API 。
示例:
-
初始化以下必需的环境变量。
user='<username>' password='<password>' region='<oci-region>' tenancy_namespace='<tenancy-namespace>' bucket_name='tutorial-bucket' object_name='sample.txt'
-
列出账户中的存储桶,将仅列出所选 OCI Swift API 区间中的存储桶。
curl -sS -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}" -u "${user}:${password}" | jq
-
创建存储桶。
curl -sS -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X PUT -u "${user}:${password}"
-
将文件上载到存储桶。
echo 'sample file' > ${object_name} curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X PUT --data-binary "@${object_name}" -u "${user}:${password}"
-
列出存储桶内容。
curl -sS -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -u "${user}:${password}" | jq
-
从存储桶中提取文件。
curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -u "${user}:${password}" -o downloaded_file.txt cat downloaded_file.txt
-
从存储桶中删除文件。
curl -sS -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X DELETE -u "${user}:${password}"
-
删除存储桶。
curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X DELETE -u "${user}:${password}"
方法 2:使用 v1 授权进行基于令牌的身份验证
您必须为区域调用 OCI Swift API 授权端点,并在请求中包括 X-Storage-User
和 X-Storage-Pass
标头。如果验证请求成功,您将收到一个响应,其中包含可用于请求授权的 X-Storage-Token
标头,以及包含账户的 OCI Swift API 端点的 X-Storage-Url
标头。
X-Storage-User
标头的格式为 <tenancy-namespace>:<username>
。
例如,如果 tenancy-namespace
为 axaxnpcrorw5
,并且用户名与方法 1 相同,则标头的值为 axaxnpcrorw5:oracleidentitycloudservice/john.doe@acme.com
。
X-Storage-Pass
是生成的验证令牌。
示例:
-
初始化以下必需的环境变量。
user='<username>' password='<password>' region='<oci-region>' tenancy_namespace='<tenancy-namespace>' bucket_name='tutorial-bucket' object_name='sample.txt'
-
生成令牌。
curl -sS -D swift_headers.txt https://swiftobjectstorage.eu-frankfurt-1.oraclecloud.com/auth/v1.0 -H "X-Storage-User: ${tenancy_namespace}:${user}" -H "X-Storage-Pass: ${password}" X_Auth_Token=$(cat swift_headers.txt | grep X-Auth-Token | cut -d":" -f 2)
-
列出账户中的存储桶,将仅列出所选 OCI Swift API 区间中的存储桶。
curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}" -H "X-Auth-Token: ${X_Auth_Token}" | jq
-
创建存储桶。
curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X PUT -H "X-Auth-Token: ${X_Auth_Token}"
-
将文件上载到存储桶。
echo 'sample file' > ${object_name} curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X PUT --data-binary "@${object_name}" -H "X-Auth-Token: ${X_Auth_Token}"
-
列出存储桶内容。
curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -H "X-Auth-Token: ${X_Auth_Token}" | jq
-
从存储桶中提取文件。
curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -H "X-Auth-Token: ${X_Auth_Token}" -o downloaded_file.txt cat downloaded_file.txt
-
从存储桶中删除文件。
curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X DELETE -H "X-Auth-Token: ${X_Auth_Token}"
-
删除存储桶。
curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X DELETE -H "X-Auth-Token: ${X_Auth_Token}"
方法 3:使用 v2 授权进行基于令牌的身份验证
为了说明 OCI Swift API v2 授权过程,我们将使用官方的 OpenStack Swift API Python 程序包 python-swiftclient 4.5.0 ,以及 v2 验证 python-keystoneclient 5.4.0 的必需依赖项。
示例:
-
运行以下命令以确保您可以访问
3.6
以上的 Python 版本。有关详细信息,请参见下载 Python 。python3 --version
-
安装所需的 Python 模块。
python3 -m pip install python-swiftclient python-keystoneclient click
-
您可以使用以下代码与 OCI Swift API v2 进行交互。在运行之前,请确保在以下代码中替换
<user>
、<password>
、<region>
和<tenancy-namespace>
的占位符。import click import os from swiftclient.client import Connection from swiftclient.exceptions import ClientException user='<username>' password='<password>' region='<oci-region>' tenancy_namespace='<tenancy-namespace>' bucket_name='tutorial-bucket' object_name='sample.txt' _authurl = f'https://swiftobjectstorage.{region}.oraclecloud.com/auth/v2.0/' _auth_version = '2' _user = f'{user}' _key = f'{password}' _tenant_name = f'{tenancy_namespace}' conn = Connection( authurl=_authurl, user=_user, key=_key, tenant_name=_tenant_name, auth_version=_auth_version ) @click.group(invoke_without_command=True) @click.pass_context def main(ctx): available_commands = { "a": ("List buckets in the account", get_account), "b": ("Create a new bucket", put_container), "c": ("Upload an object to the bucket", put_object), "d": ("List objects in the bucket", get_container), "e": ("Download object from the bucket", get_object), "f": ("Delete object from the bucket", delete_object), "g": ("Delete bucket from the account", delete_container) } while True: click.echo("Available actions") for index, command in available_commands.items(): click.echo(f"{index} - {command[0]}") action = click.prompt("Please select an option from the list") if action in available_commands.keys(): ctx.invoke(available_commands[action][1]) print("###"*10) @main.command() def get_account(conn=conn): print("Listing buckets in the account.") try: resp_headers = conn.get_account() for entry in resp_headers[1]: print(entry["name"]) except ClientException as e: print(f"Failed to get the buckets in the tenancy. Error: {e}") raise else: print(f"Successfuly listed bucket in the '{_tenant_name}' account.") @main.command() def put_container(conn=conn, bucket_name=bucket_name): print(f"Creating a new bucket named {bucket_name}.") try: resp_headers = conn.put_container(container=bucket_name) except ClientException as e: print(f"Failed to create the new bucket named {bucket_name} in the tenancy. Error: {e}") raise else: print(f"The '{bucket_name}' was successfuly created.") @main.command() def put_object(conn=conn, bucket_name=bucket_name, object_name=object_name): print(f"Uploading a new file, '{object_name}' to the new bucket '{bucket_name}'.") try: if not os.path.isfile(object_name): with open(object_name, "w") as f: f.write("sample file") with open(object_name) as f: resp_headers = conn.put_object(container=bucket_name, obj=object_name, contents=object_name) except ClientException as e: print(f"Failed to create a new object named '{object_name}' in the bucket '{bucket_name}'. Error: {e}") raise else: print(f"The '{object_name}' file was successfuly uploaded to '{bucket_name}' bucket.") @main.command() def get_container(conn=conn, bucket_name=bucket_name): print(f"List {bucket_name} bucket contents.") try: resp_headers = conn.get_container(container=bucket_name) for entry in resp_headers[1]: print(entry["name"]) except ClientException as e: print(f"Failed to list objects in the bucket {bucket_name}. Error: {e}") raise else: print(f"The '{bucket_name}' content was successfuly listed.") @main.command() def get_object(conn=conn, bucket_name=bucket_name, object_name=object_name, dest_file="downloaded_file.txt"): print(f"Fetch {object_name} object from the bucket {bucket_name}.") try: resp_headers = conn.get_object(container=bucket_name, obj=object_name) with open(dest_file, "wb") as f: f.write(resp_headers[1]) except ClientException as e: print(f"Failed to download {object_name} from {bucket_name} to local file named '{dest_file}'. Error: {e}") raise else: print(f"The '{object_name}' object was saved locally to '{dest_file}'.") @main.command() def delete_object(conn=conn, bucket_name=bucket_name, object_name=object_name): print(f"Deleting {object_name} object from the bucket {bucket_name}.") try: resp_headers = conn.delete_object(container=bucket_name, obj=object_name) except ClientException as e: print(f"Failed to delete {object_name} from {bucket_name}. Error: {e}") raise else: print(f"The '{object_name}' object was deleted.") @main.command() def delete_container(conn=conn, bucket_name=bucket_name): print(f"Deleting the bucket {bucket_name}.") try: resp_headers = conn.delete_container(container=bucket_name) except ClientException as e: print(f"Failed to delete {object_name} from {bucket_name}. Error: {e}") raise else: print(f"The '{bucket_name}' bucket was deleted.") if __name__ == "__main__": main()
相关链接
确认
- 作者 - Andrei Ilas(首席云架构师)
更多学习资源
浏览 docs.oracle.com/learn 上的其他实验室,或者通过 Oracle Learning YouTube 频道访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。
有关产品文档,请访问 Oracle 帮助中心。
Use Oracle Cloud Infrastructure Object Storage Service with OpenStack Swift API
F95069-01
March 2024