Lưu trữ đối tượng tương thích S3: trình duyệt tệp, liên kết công khai và khoá S3 theo từng tài khoản dịch vụ.
Bucket là dịch vụ lưu trữ đối tượng tương thích S3 của Nohost Cloud. Mỗi bucket chứa các file (object) được tổ chức thành thư mục, và bạn làm việc với chúng theo ba cách: qua trình duyệt file ngay trong console, qua web công khai tại một URL riêng cho mỗi bucket khi bucket ở chế độ public, và qua giao thức S3 chuẩn từ các công cụ như AWS CLI, boto3 hay bất kỳ S3 SDK nào.
Bên dưới, mỗi môi trường chạy một máy chủ S3 dùng chung duy nhất (RustFS, một triển khai tương thích MinIO). Bucket từ mọi dự án đều nằm trong cùng một máy chủ đó, nên nền tảng tách chúng ra bằng cách đặt cho mỗi bucket một tên nội bộ dạng <project>-<bid>. Trong console bạn chỉ bao giờ thấy và gõ id bucket của riêng mình, <bid> — phần tiền tố dự án được thêm vào giúp bạn. Bạn chỉ cần tên nội bộ khi nói chuyện với endpoint S3 thô (xem Kết nối qua S3).
Bucket nằm ở đâu trong console
Bucket thuộc phạm vi dự án. Mở một dự án và vào/<project>/bucket. Danh sách bucket nằm ở đó; mỗi bucket mở ra trang chi tiết riêng với ba trang con — Overview (kích thước, số object, thông tin kết nối), Files (trình duyệt file) và Permissions (quyền và khóa S3).owner hoặc editor của dự án (tương đương năng lực storage.admin). Bất kỳ thành viên dự án nào cũng có thể duyệt, liệt kê và tải xuống object qua console.Trong console, mở Bucket trong dự án của bạn và dùng Create bucket. Bạn chọn một id và bucket có public hay không. Id phải an toàn theo chuẩn S3 / DNS: chữ thường, chữ số và dấu gạch nối, 3–63 ký tự, bắt đầu và kết thúc bằng một chữ cái hoặc chữ số (regex ^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$), và duy nhất trong dự án.
| Field | Type | Description |
|---|---|---|
id | string | Id bucket bạn chọn. An toàn S3/DNS, duy nhất trong dự án. Hiển thị ở mọi nơi dưới dạng <bid>. |
public | boolean | Khi là true, object được phục vụ ẩn danh tại URL công khai. Khi là false (mặc định) bucket ở chế độ riêng tư. |
Từ REST API, cùng lời gọi đó với curl:
API=https://api.<base-domain>
TOKEN=<your project API key>
PROJECT=<project>
curl -sS -X POST "$API/api/v1/projects/$PROJECT/buckets" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":"assets","public":false}'Tạo một bucket sẽ cấp phát bucket S3 nội bộ <project>-<bid> và, nếu bạn yêu cầu public, thiết lập chính sách tải xuống ẩn danh và publish URL công khai.
Trang con Files là một trình duyệt đầy đủ cho bucket. Nó hoạt động qua backend (phiên console của bạn chính là credential), nên bạn không cần khóa S3 để dùng. Nó hỗ trợ:
/./, nên những gì bạn thấy giống một hệ thống file thông thường mặc dù key S3 thực ra là các chuỗi phẳng như images/2026/logo.png.Một bucket private (mặc định) chỉ truy cập được qua console hoặc với credential S3 hợp lệ. Một bucket public ngoài ra còn phục vụ mọi object qua HTTP GET ẩn danh tại URL công khai của nó:
https://<bid>.b5.<project>.<base-domain>/<key>
Vậy một object với key images/logo.png trong một bucket public assets ở dự án acme sẽ nằm tại https://assets.b5.acme.<base-domain>/images/logo.png. Bật hoặc tắt public từ trang chi tiết bucket; bật nó lên sẽ tạo route công khai và chính sách ẩn danh, tắt nó đi sẽ gỡ chúng để bucket trở lại riêng tư.
Public nghĩa là ai cũng đọc được
Một bucket public cho phép tải xuống ẩn danh mọi object trong nó — không có khả năng phân quyền hiển thị theo từng object. Đừng đặt bí mật, dữ liệu cá nhân hay bất cứ thứ gì bạn không muốn dán lên web công khai vào một bucket public. Public chỉ mở quyền đọc (GET); tải lên và xóa vẫn cần credential.Trang con Permissions kiểm soát truy cập qua giao thức S3 — tức là truy cập cho các client bên ngoài dùng một service account, không phải thành viên console. Nó có hai phần: các quyền (grant) theo thư mục và các khóa S3 theo từng service account.
Một grant giới hạn một service account vào một tiền tố thư mục với một mức truy cập. Thêm một grant bằng cách chọn một service account, một tiền tố (để trống nghĩa là toàn bộ bucket), và một mức truy cập:
read — liệt kê và tải xuống dưới tiền tố.write — tải lên và xóa dưới tiền tố.readwrite — cả hai.Ví dụ, cấp cho service account ci tiền tố builds/ với readwrite cho phép account đó đọc và ghi mọi thứ dưới builds/ và không gì ngoài đó. Grant chỉ ảnh hưởng tới các client giao thức S3 — thành viên console đã có quyền ở cấp dự án và không bị ảnh hưởng.
Để thực sự kết nối, mỗi service account cần một cặp khóa truy cập/bí mật S3. Dùng Issue key bên cạnh một service account. Khóa truy cập và endpoint được hiển thị sau đó, nhưng khóa bí mật chỉ hiển thị đúng một lần, vào thời điểm cấp. Hãy sao chép nó ngay lập tức và cất ở nơi an toàn — nền tảng không giữ nó và không thể hiển thị lại. Nếu bạn làm mất nó, dùng Rotate key để cấp một cặp mới (việc này vô hiệu hóa cặp cũ), hoặc Revoke để gỡ bỏ hoàn toàn truy cập S3.
Khóa bí mật chỉ hiển thị một lần
Không có cách nào khôi phục khóa bí mật sau khi hộp thoại hiển thị đóng lại. Rotate hoặc revoke sẽ vô hiệu hóa khóa trước đó ngay lập tức, nên bất kỳ client nào vẫn dùng nó sẽ bắt đầu nhậnAccessDenied.Khóa của một service account luôn mang chính sách được tính từ các grant hiện tại của nó. Thêm hoặc gỡ một grant thì quyền hiệu lực của khóa cập nhật tự động — bạn không cần cấp lại nó.
Bất kỳ S3 client nào cũng có thể nói chuyện với một bucket bằng khóa của một service account. Endpoint là một URL S3 kiểu path-style dùng chung duy nhất cho toàn môi trường, và bạn địa chỉ hóa bucket của mình bằng tên nội bộ <project>-<bid>.
| Setting | Giá trị |
|---|---|
Endpoint | https://s3.b5.<base-domain> (path-style) |
Region | us-east-1 |
Bucket | Tên nội bộ <project>-<bid> — ví dụ acme-assets |
Access key | Khóa truy cập S3 được cấp trên trang Permissions |
Secret key | Khóa bí mật tương ứng, chỉ hiển thị một lần lúc cấp |
Addressing | Path-style — force-path-style / s3ForcePathStyle = true |
Endpoint, region và tên bucket nội bộ chính xác cũng được hiển thị trên trang Overview của bucket để bạn có thể sao chép trực tiếp.
# Configure a profile from the issued key pair
aws configure set aws_access_key_id <access-key> --profile nohost
aws configure set aws_secret_access_key <secret-key> --profile nohost
aws configure set region us-east-1 --profile nohost
ENDPOINT=https://s3.b5.<base-domain>
BUCKET=<project>-<bid> # internal name, e.g. acme-assets
# List, upload, download — note --endpoint-url
aws --profile nohost s3 --endpoint-url $ENDPOINT ls s3://$BUCKET/
aws --profile nohost s3 --endpoint-url $ENDPOINT cp ./logo.png s3://$BUCKET/images/logo.png
aws --profile nohost s3 --endpoint-url $ENDPOINT cp s3://$BUCKET/images/logo.png ./logo.pngTruy cập bị giới hạn trong các tiền tố bạn được cấp: một lệnh s3 cp ngoài chúng trả về AccessDenied.
Trỏ client vào endpoint path-style và dùng tên bucket nội bộ. Cùng một mẫu áp dụng cho mọi S3 SDK — đặt endpoint, region us-east-1 và bật địa chỉ hóa path-style.
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
endpoint_url="https://s3.b5.<base-domain>",
aws_access_key_id="<access-key>",
aws_secret_access_key="<secret-key>",
region_name="us-east-1",
config=Config(s3={"addressing_style": "path"}),
)
bucket = "<project>-<bid>" # internal name, e.g. acme-assets
s3.upload_file("logo.png", bucket, "images/logo.png")
for obj in s3.list_objects_v2(Bucket=bucket, Prefix="images/").get("Contents", []):
print(obj["Key"], obj["Size"])Code chạy trong một function Kinetic hoặc một Dev Box truy cập bucket theo đúng cùng một cách — không có lối tắt đặc biệt nào trong cluster, vẫn là cùng endpoint S3 và một khóa service account. Cấp một khóa S3 cho một service account, grant cho nó các tiền tố mà workload cần, và cung cấp credential dưới dạng biến môi trường.
S3_ENDPOINT=https://s3.b5.<base-domain>
S3_REGION=us-east-1
S3_BUCKET=<project>-<bid>
AWS_ACCESS_KEY_ID=<access-key>
AWS_SECRET_ACCESS_KEY=<secret-key>read nếu nó không bao giờ ghi). Nếu một credential bị lộ bạn có thể rotate hoặc revoke chỉ riêng account đó mà không động đến bất cứ thứ gì khác.Mọi thứ console làm đều có sẵn qua REST dưới /api/v1/projects/{project}/buckets. Xác thực bằng một project API key dưới dạng bearer token. Cùng quy tắc vai trò áp dụng: đọc cần bất kỳ tư cách thành viên nào, ghi cần owner/editor. Các ví dụ dưới đây giả định:
API=https://api.<base-domain>
TOKEN=<your project API key>
PROJECT=<project>
BID=<bid>
AUTH="Authorization: Bearer $TOKEN"# List buckets (also returns disk quota, usage and readonly state)
curl -sS "$API/api/v1/projects/$PROJECT/buckets" -H "$AUTH"
# Create a bucket
curl -sS -X POST "$API/api/v1/projects/$PROJECT/buckets" -H "$AUTH" \
-H "Content-Type: application/json" \
-d '{"id":"assets","public":false}'
# Get one bucket (includes connection info: endpoint, region, internal name)
curl -sS "$API/api/v1/projects/$PROJECT/buckets/$BID" -H "$AUTH"
# Toggle public on/off
curl -sS -X PATCH "$API/api/v1/projects/$PROJECT/buckets/$BID" -H "$AUTH" \
-H "Content-Type: application/json" -d '{"public":true}'
# Delete a bucket (empties it first)
curl -sS -X DELETE "$API/api/v1/projects/$PROJECT/buckets/$BID" -H "$AUTH"# List one folder level (delimiter "/"); omit prefix for the root
curl -sS "$API/api/v1/projects/$PROJECT/buckets/$BID/objects?prefix=images/" -H "$AUTH"
# Upload (multipart form, field name "file") into a prefix
curl -sS -X POST "$API/api/v1/projects/$PROJECT/buckets/$BID/objects?prefix=images/" \
-H "$AUTH" -F "file=@logo.png"
# Download (stream) a single object by key
curl -sS "$API/api/v1/projects/$PROJECT/buckets/$BID/objects/raw?key=images/logo.png" \
-H "$AUTH" -o logo.png
# Delete an object (or a folder if the key ends with "/")
curl -sS -X DELETE "$API/api/v1/projects/$PROJECT/buckets/$BID/objects?key=images/logo.png" -H "$AUTH"
# Create an (empty) folder
curl -sS -X POST "$API/api/v1/projects/$PROJECT/buckets/$BID/folders?prefix=images/" \
-H "$AUTH" -H "Content-Type: application/json" -d '{"name":"thumbnails"}'# List grants on a bucket
curl -sS "$API/api/v1/projects/$PROJECT/buckets/$BID/grants" -H "$AUTH"
# Add / update a grant (upsert) for a service account
curl -sS -X POST "$API/api/v1/projects/$PROJECT/buckets/$BID/grants" -H "$AUTH" \
-H "Content-Type: application/json" \
-d '{"saId":"<sa-id>","prefix":"builds/","access":"readwrite"}'
# Remove a grant
curl -sS -X DELETE "$API/api/v1/projects/$PROJECT/buckets/$BID/grants/<grant-id>" -H "$AUTH"
# S3 key for a service account: get status (does NOT return the secret)
curl -sS "$API/api/v1/projects/$PROJECT/service-accounts/<sa-id>/s3-key" -H "$AUTH"
# Issue / rotate the key — secretKey is returned ONCE in this response
curl -sS -X POST "$API/api/v1/projects/$PROJECT/service-accounts/<sa-id>/s3-key" -H "$AUTH"
# Revoke the key
curl -sS -X DELETE "$API/api/v1/projects/$PROJECT/service-accounts/<sa-id>/s3-key" -H "$AUTH"Phản hồi issue/rotate trông như sau:
{
"accessKey": "AKIA...EXAMPLE",
"secretKey": "wq8s...shown-once",
"endpoint": "https://s3.b5.<base-domain>",
"region": "us-east-1"
}Toàn bộ dung lượng lưu trữ bucket trong một dự án được tính vào quota Disk của dự án đó. Khi tổng mức dùng vượt quota, nền tảng đưa mọi bucket trong dự án vào chế độ chỉ-đọc cho đến khi mức dùng giảm về dưới giới hạn. Trong khi chỉ-đọc:
409 và thông báo project is read-only: disk quota exceeded.AccessDenied — chính sách trên mọi khóa service account tự động bị tước các action ghi.Khôi phục bằng cách xóa object để trở lại dưới quota, hoặc bằng cách nâng quota Disk cho dự án; ở chu kỳ tính phí tiếp theo dự án sẽ chuyển lại thành ghi được và một sự kiện được ghi nhận. Lưu ý rằng mức dùng đĩa so với quota được hiển thị trên trang Tính phí, không phải trên các trang bucket.
Tải lên lớn thất bại với 502 hoặc lỗi kích thước body
Các lần tải lên rất lớn có thể chạm giới hạn kích thước body của proxy trên route tải lên của console và trả về502 hoặc lỗi request-entity-too-large. Với file lớn, hãy tải lên qua giao thức S3 thay thế (aws s3 cp / SDK hỗ trợ multipart) tới endpoint S3, vốn được cấu hình để chấp nhận body lớn.409 'project is read-only: disk quota exceeded'
Dự án đã vượt quota Disk và mọi bucket ở chế độ chỉ-đọc. Hãy xóa object hoặc nâng quota; xem Quota Disk & chế độ chỉ-đọc.Mất khóa bí mật / S3 client nhận AccessDenied
Khóa bí mật chỉ hiển thị một lần lúc cấp và không bao giờ được lưu. Nếu bạn làm mất nó, Rotate key để tạo một cặp mới (rồi cập nhật client của bạn).AccessDenied trên một đường dẫn bạn nghĩ phải hoạt động thường nghĩa là request nằm ngoài một tiền tố được cấp, khóa đã bị rotate/revoke, hoặc dự án đang chỉ-đọc — hãy kiểm tra tiền tố grant, cấp lại khóa, và xác nhận quota.<project>-<bid> và luôn bật địa chỉ hóa path-style — kiểu virtual-host (<bucket>.s3...) sẽ không phân giải được.