diff --git a/.agents/skills/localize-rustfs-docs/SKILL.md b/.agents/skills/localize-rustfs-docs/SKILL.md new file mode 100644 index 000000000..53f4c3f93 --- /dev/null +++ b/.agents/skills/localize-rustfs-docs/SKILL.md @@ -0,0 +1,74 @@ +--- +name: localize-rustfs-docs +description: Localize, add, review, or repair RustFS documentation languages and FumaPress internationalization. Use for locale directories, translated Markdown or MDX, localized navigation and UI, terminology decisions, language routing, hreflang metadata, search indexes, redirects, and translation-quality reviews in docs.rustfs.com. +--- + +# Localize RustFS documentation + +Build each locale as a complete RustFS documentation experience. Preserve product meaning and operational accuracy; do not perform literal sentence-by-sentence substitution. + +## Required context + +1. Read `../rustfs-docs/SKILL.md` and the repository `STYLE.md` before editing content. +2. Read [the current FumaPress internationalization guide](https://press.fumadocs.dev/docs/internationalization.md) before changing `press.config.tsx` or locale layout. +3. Read [references/terminology.md](references/terminology.md) before translating or reviewing terminology. +4. Verify commands, flags, configuration keys, defaults, ports, APIs, and feature claims against `rustfs/rustfs`; never infer them from a translation. + +## Translation standard + +- Translate meaning in the context of the RustFS product, its Console, and S3-compatible behavior. Rewrite sentence structure when necessary for natural target-language documentation. +- Keep `RustFS`, protocol names, API names, CLI commands, code, environment variables, configuration keys, file paths, URLs, JSON/YAML keys, and identifiers unchanged. +- Use the glossary consistently. When a technical term has no established translation, keep the English term and add a short target-language explanation on first use. +- Preserve visible Console labels exactly when instructing the reader to click them; add a translation in parentheses only when it improves comprehension. +- Preserve the source page's technical scope. Do not add capabilities, defaults, warnings, or recommendations during translation unless they are verified and added to every maintained locale. +- Keep code fences byte-for-byte equivalent across locales unless a localized string is itself part of the demonstrated behavior. Translate prose outside code fences instead. +- Preserve links and cited sources. Localize internal documentation links to the current locale while keeping external destinations unchanged. +- Review the completed page as native technical writing. Reject awkward calques, ambiguous pronouns, untranslated prose fragments, terminology drift, and sentences that are grammatically correct but unnatural. + +## Configure FumaPress i18n + +1. Define all locales with `defineI18n` and choose the parser explicitly. This repository uses locale directories, so keep `parser: "dir"`. +2. Pass the resulting translations API to `defineConfig`. +3. Use an official `@fumapress/language` preset when available. A preset localizes Fumadocs UI and FumaPress strings; setting only `displayName` is insufficient. +4. Localize repository-owned navigation, footer text, labels, and calls to action separately because language packs cannot translate hard-coded strings. +5. Keep `content//` trees structurally aligned. Every maintained page must have a target-locale counterpart or an explicitly documented fallback decision. +6. Emit the correct ``, canonical URL, and `hreflang` alternates for every page. +7. Verify that search output is partitioned by locale and that the language switcher retains the corresponding page path. + +## Content and navigation workflow + +1. Start from the current default-language page, not from an older translation. +2. Identify RustFS-specific terms and runtime claims before translating. +3. Translate headings and prose for reader intent, then reconcile terminology against the glossary and nearby translated pages. +4. Copy or share required images without changing the English, light-theme screenshot policy from `rustfs-docs`. +5. Update the target locale's `meta.json`. Use bare entries for pages inside the same folder; use locale-prefixed URLs for cross-folder navigation entries. +6. Check that frontmatter, heading levels, admonitions, links, images, code-fence languages, and MDX component structure match the source page. +7. Review the rendered page, including sidebar, breadcrumbs, table of contents, previous/next links, search, and custom navbar/footer text. + +## Routing and deployment + +- Keep locale prefixes explicit (`/en/...`, `/zh/...`) while `hideLocale: "never"` is configured. +- Redirect `/` to the default locale and preserve every historical unprefixed URL by redirecting it to the equivalent default-locale URL. +- Treat hosting configuration as part of i18n. `_redirects` is used by Cloudflare-style static hosting; Vercel requires `vercel.json`, `vercel.ts`, or a configured bulk redirects file. +- Never delete a legacy redirect merely because the destination gained a locale prefix. Prefix its destination and retain the original source. +- Smoke-test redirects against the deployed preview. A successful build or deployment status does not prove that redirects work. + +## Validation + +Run all repository checks: + +```bash +npm run docs:check +npm run types:check +npm run build +``` + +Then verify: + +- `content/en` and every maintained locale contain the same relative file set. +- Commands and non-localized code blocks remain identical across translated counterparts. +- Every generated internal `href` resolves to a generated page or public asset. +- Target-language pages do not expose unexpected English framework UI strings. +- `/`, representative legacy URLs, and representative locale URLs return the intended status and destination on the deployment preview. + +Do not commit `node_modules/`, `dist/`, preview output, or temporary translation files. diff --git a/.agents/skills/localize-rustfs-docs/agents/openai.yaml b/.agents/skills/localize-rustfs-docs/agents/openai.yaml new file mode 100644 index 000000000..07b4e31e9 --- /dev/null +++ b/.agents/skills/localize-rustfs-docs/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Localize RustFS Docs" + short_description: "Build and verify localized RustFS documentation" + default_prompt: "Use $localize-rustfs-docs to add or review a documentation locale end to end." diff --git a/.agents/skills/localize-rustfs-docs/references/terminology.md b/.agents/skills/localize-rustfs-docs/references/terminology.md new file mode 100644 index 000000000..63fef5a8c --- /dev/null +++ b/.agents/skills/localize-rustfs-docs/references/terminology.md @@ -0,0 +1,65 @@ +# RustFS localization terminology + +Use this hierarchy when choosing a translation: + +1. The term used by the current RustFS product, Console, source code, or API. +2. An established term already used consistently in the target-language RustFS documentation. +3. The standard term used by the relevant ecosystem, such as Amazon S3 or Kubernetes. +4. English with a concise target-language explanation when no stable translation exists. + +Never choose a dictionary translation that changes the RustFS concept. Search the repository and upstream source before adding a new translation, and update this glossary when a new term becomes canonical. + +## Simplified Chinese baseline + +| Source term | Preferred Chinese | Guidance | +|---|---|---| +| RustFS | RustFS | Never translate or alter capitalization. | +| Amazon S3 / S3 | Amazon S3 / S3 | Keep the product and protocol name. | +| S3-compatible | 兼容 S3 | Do not claim complete or 100% compatibility. | +| object storage | 对象存储 | Use for the storage model. | +| bucket | 存储桶 | Use consistently in prose. Preserve `bucket` in code and API names. | +| object | 对象 | Use for an S3 object; do not substitute “file” unless the source specifically means a local file. | +| object key | 对象键 | Keep `Key` unchanged in API or JSON examples. | +| access key | 访问密钥 | Preserve `RUSTFS_ACCESS_KEY` and SDK field names. | +| secret key | 秘密密钥 | Preserve `RUSTFS_SECRET_KEY` and SDK field names. | +| Console | 控制台 | Keep visible English UI labels unchanged in step instructions. | +| endpoint | 端点 | Use “S3 API 端点” when the endpoint type could be ambiguous. | +| region | 区域 | Preserve region values such as `us-east-1`. | +| tenant | 租户 | Use in the RustFS Operator and multi-tenancy context. | +| storage pool | 存储池 | Do not shorten to “池” when the storage meaning is unclear. | +| erasure coding | 纠删码 | Use for the data-protection scheme. | +| healing | 修复 | Use for RustFS data or node recovery operations; do not translate as medical “healing”. | +| rebalance | 数据再平衡 | Use “再平衡” for the operation name when context is already clear. | +| decommission | 退役 | Use the established RustFS operation name “存储池退役”; explain that the pool is drained and deactivated rather than substituting a generic “下线”. | +| replication | 复制 | Qualify as “站点复制” or “存储桶复制” according to the RustFS feature. | +| versioning | 版本控制 | Use specifically for S3 object versioning. | +| object lock | 对象锁定 | Do not conflate with distributed locks. | +| legal hold | 依法保留 | Use the established Amazon S3 Chinese term; preserve API names such as `ObjectLockLegalHold`. | +| lifecycle management | 生命周期管理 | Use for S3 lifecycle rules. | +| IAM | IAM | Keep the acronym; explain as identity and access management on first conceptual use. | +| KMS | KMS | Keep the acronym; distinguish RustFS built-in KMS from external backends. | +| STS | STS | Keep the acronym; explain temporary credentials when needed. | +| OIDC | OIDC | Keep the acronym and protocol terminology. | +| server-side encryption | 服务端加密 | Keep SSE-S3, SSE-KMS, and SSE-C unchanged. | +| path-style addressing | 路径式寻址 | Preserve SDK option names such as `forcePathStyle`. | +| virtual-hosted-style addressing | 虚拟主机式寻址 | Relate it to `RUSTFS_SERVER_DOMAINS` when relevant. | +| presigned URL | 预签名 URL | Keep URL uppercase. | +| multipart upload | 分片上传 | Use the established S3 term. | +| health check | 健康检查 | Keep endpoint paths unchanged. | +| readiness | 就绪状态 | Use for readiness probes and `/health/ready`. | +| observability | 可观测性 | Keep OpenTelemetry and OTLP unchanged. | +| webhook | Webhook | Prefer the established English product term over a literal translation. | +| rootless | 无 root 权限 | In Podman context, prefer this over the ambiguous literal “无根”. | +| root credentials | 根凭证 | Use for the deployment-wide `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` pair; do not confuse it with an operating-system root account. | + +## UI labels and identifiers + +When the Console screenshot or interface displays an English label, write instructions like `Select **Buckets(存储桶)**` rather than translating the clickable label to a string the reader cannot find. Keep exact casing for buttons, menu items, resource kinds, and error messages. + +Do not translate identifiers embedded in prose, including: + +- executable and command names such as `rustfs`, `rc`, `aws`, and `kubectl`; +- Kubernetes resource kinds such as `Tenant`, `Secret`, and `PersistentVolumeClaim`; +- environment variables and flags; +- API actions, HTTP methods, status text, metric names, and JSON/YAML keys; +- filenames, paths, package names, image tags, domains, and URLs. diff --git a/.claude/skills/localize-rustfs-docs b/.claude/skills/localize-rustfs-docs new file mode 120000 index 000000000..f4b04b4b5 --- /dev/null +++ b/.claude/skills/localize-rustfs-docs @@ -0,0 +1 @@ +../../.agents/skills/localize-rustfs-docs \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index fdc0aa760..a62d300c5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ This playbook directs AI agents working in the RustFS documentation repository so that every deliverable stays accurate, auditable, and easy to maintain. -> **Every agent:** the operating playbook for writing and reviewing these docs is the skill at [`.agents/skills/rustfs-docs/SKILL.md`](.agents/skills/rustfs-docs/SKILL.md) — factual-accuracy discipline, canonical constants, FumaPress syntax, screenshots, and the `npm run docs:check` / `npm run build` pre-flight. Read it before changing anything under `content/`. It uses the cross-client `.agents/skills/` convention; Claude Code auto-loads it via the `.claude/skills/rustfs-docs` symlink, and other agents should open the file directly. See also `STYLE.md` for the detailed style guide. +> **Every agent:** the operating playbook for writing and reviewing these docs is the skill at [`.agents/skills/rustfs-docs/SKILL.md`](.agents/skills/rustfs-docs/SKILL.md) — factual-accuracy discipline, canonical constants, FumaPress syntax, screenshots, and the `npm run docs:check` / `npm run build` pre-flight. Read it before changing anything under `content/`. For translations, locale structure, language UI, or internationalized routing, also read [`.agents/skills/localize-rustfs-docs/SKILL.md`](.agents/skills/localize-rustfs-docs/SKILL.md). It requires product-context translation instead of literal substitution and defines the RustFS terminology workflow. Skills use the cross-client `.agents/skills/` convention; Claude Code auto-loads them through matching `.claude/skills/` symlinks, and other agents should open the files directly. See also `STYLE.md` for the detailed style guide. ## 1. Repository Snapshot - Framework: **FumaPress** (static-site generator powered by Waku + Fumadocs). Content lives in `content/`; site configuration is in `press.config.tsx`, `source.config.ts`, and `waku.config.ts`. diff --git a/content/developer/examples/meta.json b/content/developer/examples/meta.json deleted file mode 100644 index 4742275a0..000000000 --- a/content/developer/examples/meta.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Examples", - "pages": [ - "[rc](/operations/rc)", - "[AWS CLI](/developer/examples/aws-cli)", - "[s3cmd](/developer/examples/s3cmd)", - "[rclone](/developer/examples/rclone)", - "[boto3 (Python)](/developer/examples/boto3)", - "[AWS SDK for JavaScript](/developer/examples/aws-sdk-js)", - "[AWS SDK for Go](/developer/examples/aws-sdk-go)", - "[Terraform](/developer/examples/terraform)" - ] -} diff --git a/content/developer/sdk/meta.json b/content/developer/sdk/meta.json deleted file mode 100644 index b93ad1cf0..000000000 --- a/content/developer/sdk/meta.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "SDK", - "pages": [ - "[Java](/developer/sdk/java)", - "[Python](/developer/sdk/python)", - "[Rust](/developer/sdk/rust)", - "[JavaScript](/developer/sdk/javascript)", - "[TypeScript](/developer/sdk/typescript)", - "[Golang](/developer/sdk/go)", - "[Other SDKs](/developer/sdk/other)" - ] -} diff --git a/content/administration/console/images/rustfs-console-login.png b/content/en/administration/console/images/rustfs-console-login.png similarity index 100% rename from content/administration/console/images/rustfs-console-login.png rename to content/en/administration/console/images/rustfs-console-login.png diff --git a/content/administration/console/index.md b/content/en/administration/console/index.md similarity index 100% rename from content/administration/console/index.md rename to content/en/administration/console/index.md diff --git a/content/administration/cors/index.md b/content/en/administration/cors/index.md similarity index 100% rename from content/administration/cors/index.md rename to content/en/administration/cors/index.md diff --git a/content/administration/data/bucket/creation.md b/content/en/administration/data/bucket/creation.md similarity index 100% rename from content/administration/data/bucket/creation.md rename to content/en/administration/data/bucket/creation.md diff --git a/content/administration/data/bucket/deletion.md b/content/en/administration/data/bucket/deletion.md similarity index 100% rename from content/administration/data/bucket/deletion.md rename to content/en/administration/data/bucket/deletion.md diff --git a/content/administration/data/bucket/images/bucket-creation-by-ui.png b/content/en/administration/data/bucket/images/bucket-creation-by-ui.png similarity index 100% rename from content/administration/data/bucket/images/bucket-creation-by-ui.png rename to content/en/administration/data/bucket/images/bucket-creation-by-ui.png diff --git a/content/administration/data/bucket/images/bucket-deletion-on-ui.png b/content/en/administration/data/bucket/images/bucket-deletion-on-ui.png similarity index 100% rename from content/administration/data/bucket/images/bucket-deletion-on-ui.png rename to content/en/administration/data/bucket/images/bucket-deletion-on-ui.png diff --git a/content/administration/data/bucket/images/bucket-quota-console.png b/content/en/administration/data/bucket/images/bucket-quota-console.png similarity index 100% rename from content/administration/data/bucket/images/bucket-quota-console.png rename to content/en/administration/data/bucket/images/bucket-quota-console.png diff --git a/content/administration/data/bucket/meta.json b/content/en/administration/data/bucket/meta.json similarity index 100% rename from content/administration/data/bucket/meta.json rename to content/en/administration/data/bucket/meta.json diff --git a/content/administration/data/bucket/policy.md b/content/en/administration/data/bucket/policy.md similarity index 100% rename from content/administration/data/bucket/policy.md rename to content/en/administration/data/bucket/policy.md diff --git a/content/administration/data/bucket/quota.md b/content/en/administration/data/bucket/quota.md similarity index 100% rename from content/administration/data/bucket/quota.md rename to content/en/administration/data/bucket/quota.md diff --git a/content/administration/data/bucket/replication.md b/content/en/administration/data/bucket/replication.md similarity index 100% rename from content/administration/data/bucket/replication.md rename to content/en/administration/data/bucket/replication.md diff --git a/content/administration/data/lifecycle-management.md b/content/en/administration/data/lifecycle-management.md similarity index 100% rename from content/administration/data/lifecycle-management.md rename to content/en/administration/data/lifecycle-management.md diff --git a/content/administration/data/meta.json b/content/en/administration/data/meta.json similarity index 100% rename from content/administration/data/meta.json rename to content/en/administration/data/meta.json diff --git a/content/administration/data/object/creation.md b/content/en/administration/data/object/creation.md similarity index 100% rename from content/administration/data/object/creation.md rename to content/en/administration/data/object/creation.md diff --git a/content/administration/data/object/deletion.md b/content/en/administration/data/object/deletion.md similarity index 100% rename from content/administration/data/object/deletion.md rename to content/en/administration/data/object/deletion.md diff --git a/content/administration/data/object/images/delete_file_from_ui.png b/content/en/administration/data/object/images/delete_file_from_ui.png similarity index 100% rename from content/administration/data/object/images/delete_file_from_ui.png rename to content/en/administration/data/object/images/delete_file_from_ui.png diff --git a/content/administration/data/object/images/multipart-upload-console.png b/content/en/administration/data/object/images/multipart-upload-console.png similarity index 100% rename from content/administration/data/object/images/multipart-upload-console.png rename to content/en/administration/data/object/images/multipart-upload-console.png diff --git a/content/administration/data/object/images/object-lock-create-bucket.png b/content/en/administration/data/object/images/object-lock-create-bucket.png similarity index 100% rename from content/administration/data/object/images/object-lock-create-bucket.png rename to content/en/administration/data/object/images/object-lock-create-bucket.png diff --git a/content/administration/data/object/images/object_details_info.png b/content/en/administration/data/object/images/object_details_info.png similarity index 100% rename from content/administration/data/object/images/object_details_info.png rename to content/en/administration/data/object/images/object_details_info.png diff --git a/content/administration/data/object/images/upload_file_from_ui.png b/content/en/administration/data/object/images/upload_file_from_ui.png similarity index 100% rename from content/administration/data/object/images/upload_file_from_ui.png rename to content/en/administration/data/object/images/upload_file_from_ui.png diff --git a/content/administration/data/object/meta.json b/content/en/administration/data/object/meta.json similarity index 100% rename from content/administration/data/object/meta.json rename to content/en/administration/data/object/meta.json diff --git a/content/administration/data/object/multipart-upload.md b/content/en/administration/data/object/multipart-upload.md similarity index 100% rename from content/administration/data/object/multipart-upload.md rename to content/en/administration/data/object/multipart-upload.md diff --git a/content/administration/data/object/object-lock.md b/content/en/administration/data/object/object-lock.md similarity index 100% rename from content/administration/data/object/object-lock.md rename to content/en/administration/data/object/object-lock.md diff --git a/content/administration/data/object/scanner.md b/content/en/administration/data/object/scanner.md similarity index 100% rename from content/administration/data/object/scanner.md rename to content/en/administration/data/object/scanner.md diff --git a/content/administration/data/object/versioning.md b/content/en/administration/data/object/versioning.md similarity index 100% rename from content/administration/data/object/versioning.md rename to content/en/administration/data/object/versioning.md diff --git a/content/administration/data/tiered-storage.md b/content/en/administration/data/tiered-storage.md similarity index 100% rename from content/administration/data/tiered-storage.md rename to content/en/administration/data/tiered-storage.md diff --git a/content/administration/index.md b/content/en/administration/index.md similarity index 100% rename from content/administration/index.md rename to content/en/administration/index.md diff --git a/content/administration/meta.json b/content/en/administration/meta.json similarity index 53% rename from content/administration/meta.json rename to content/en/administration/meta.json index 18fcca574..1178253c4 100644 --- a/content/administration/meta.json +++ b/content/en/administration/meta.json @@ -2,10 +2,10 @@ "title": "Administration", "defaultOpen": true, "pages": [ - "[Console](/administration/console)", + "[Console](/en/administration/console)", "data", "protocols", "cors", - "[Virtual-Host Access](/integration/virtual)" + "[Virtual-Host Access](/en/integration/virtual)" ] } \ No newline at end of file diff --git a/content/administration/protocols/ftps.md b/content/en/administration/protocols/ftps.md similarity index 100% rename from content/administration/protocols/ftps.md rename to content/en/administration/protocols/ftps.md diff --git a/content/administration/protocols/meta.json b/content/en/administration/protocols/meta.json similarity index 72% rename from content/administration/protocols/meta.json rename to content/en/administration/protocols/meta.json index f1395739f..860caa6fe 100644 --- a/content/administration/protocols/meta.json +++ b/content/en/administration/protocols/meta.json @@ -5,6 +5,6 @@ "webdav", "ftps", "sftp", - "[MCP Server](/developer/mcp)" + "[MCP Server](/en/developer/mcp)" ] } \ No newline at end of file diff --git a/content/administration/protocols/s3.md b/content/en/administration/protocols/s3.md similarity index 100% rename from content/administration/protocols/s3.md rename to content/en/administration/protocols/s3.md diff --git a/content/administration/protocols/sftp.md b/content/en/administration/protocols/sftp.md similarity index 100% rename from content/administration/protocols/sftp.md rename to content/en/administration/protocols/sftp.md diff --git a/content/administration/protocols/webdav.md b/content/en/administration/protocols/webdav.md similarity index 100% rename from content/administration/protocols/webdav.md rename to content/en/administration/protocols/webdav.md diff --git a/content/developer/examples/aws-cli.md b/content/en/developer/examples/aws-cli.md similarity index 100% rename from content/developer/examples/aws-cli.md rename to content/en/developer/examples/aws-cli.md diff --git a/content/developer/examples/aws-sdk-go.md b/content/en/developer/examples/aws-sdk-go.md similarity index 100% rename from content/developer/examples/aws-sdk-go.md rename to content/en/developer/examples/aws-sdk-go.md diff --git a/content/developer/examples/aws-sdk-js.md b/content/en/developer/examples/aws-sdk-js.md similarity index 100% rename from content/developer/examples/aws-sdk-js.md rename to content/en/developer/examples/aws-sdk-js.md diff --git a/content/developer/examples/boto3.md b/content/en/developer/examples/boto3.md similarity index 100% rename from content/developer/examples/boto3.md rename to content/en/developer/examples/boto3.md diff --git a/content/en/developer/examples/meta.json b/content/en/developer/examples/meta.json new file mode 100644 index 000000000..ae59fba85 --- /dev/null +++ b/content/en/developer/examples/meta.json @@ -0,0 +1,13 @@ +{ + "title": "Examples", + "pages": [ + "[rc](/en/operations/rc)", + "[AWS CLI](/en/developer/examples/aws-cli)", + "[s3cmd](/en/developer/examples/s3cmd)", + "[rclone](/en/developer/examples/rclone)", + "[boto3 (Python)](/en/developer/examples/boto3)", + "[AWS SDK for JavaScript](/en/developer/examples/aws-sdk-js)", + "[AWS SDK for Go](/en/developer/examples/aws-sdk-go)", + "[Terraform](/en/developer/examples/terraform)" + ] +} diff --git a/content/developer/examples/rclone.md b/content/en/developer/examples/rclone.md similarity index 100% rename from content/developer/examples/rclone.md rename to content/en/developer/examples/rclone.md diff --git a/content/developer/examples/s3cmd.md b/content/en/developer/examples/s3cmd.md similarity index 100% rename from content/developer/examples/s3cmd.md rename to content/en/developer/examples/s3cmd.md diff --git a/content/developer/examples/terraform.md b/content/en/developer/examples/terraform.md similarity index 100% rename from content/developer/examples/terraform.md rename to content/en/developer/examples/terraform.md diff --git a/content/developer/images/add-rustfs-mcp-succ.png b/content/en/developer/images/add-rustfs-mcp-succ.png similarity index 100% rename from content/developer/images/add-rustfs-mcp-succ.png rename to content/en/developer/images/add-rustfs-mcp-succ.png diff --git a/content/developer/images/list-rustfs-bucket-with-mcp.png b/content/en/developer/images/list-rustfs-bucket-with-mcp.png similarity index 100% rename from content/developer/images/list-rustfs-bucket-with-mcp.png rename to content/en/developer/images/list-rustfs-bucket-with-mcp.png diff --git a/content/developer/index.md b/content/en/developer/index.md similarity index 100% rename from content/developer/index.md rename to content/en/developer/index.md diff --git a/content/developer/integration/big-data/iceberg.md b/content/en/developer/integration/big-data/iceberg.md similarity index 100% rename from content/developer/integration/big-data/iceberg.md rename to content/en/developer/integration/big-data/iceberg.md diff --git a/content/developer/integration/big-data/index.md b/content/en/developer/integration/big-data/index.md similarity index 100% rename from content/developer/integration/big-data/index.md rename to content/en/developer/integration/big-data/index.md diff --git a/content/developer/integration/big-data/meta.json b/content/en/developer/integration/big-data/meta.json similarity index 100% rename from content/developer/integration/big-data/meta.json rename to content/en/developer/integration/big-data/meta.json diff --git a/content/developer/integration/big-data/milvus.md b/content/en/developer/integration/big-data/milvus.md similarity index 100% rename from content/developer/integration/big-data/milvus.md rename to content/en/developer/integration/big-data/milvus.md diff --git a/content/developer/integration/index.md b/content/en/developer/integration/index.md similarity index 100% rename from content/developer/integration/index.md rename to content/en/developer/integration/index.md diff --git a/content/developer/integration/meta.json b/content/en/developer/integration/meta.json similarity index 100% rename from content/developer/integration/meta.json rename to content/en/developer/integration/meta.json diff --git a/content/developer/integration/reverse-proxy/caddy.md b/content/en/developer/integration/reverse-proxy/caddy.md similarity index 100% rename from content/developer/integration/reverse-proxy/caddy.md rename to content/en/developer/integration/reverse-proxy/caddy.md diff --git a/content/developer/integration/reverse-proxy/haproxy.md b/content/en/developer/integration/reverse-proxy/haproxy.md similarity index 100% rename from content/developer/integration/reverse-proxy/haproxy.md rename to content/en/developer/integration/reverse-proxy/haproxy.md diff --git a/content/developer/integration/reverse-proxy/index.md b/content/en/developer/integration/reverse-proxy/index.md similarity index 100% rename from content/developer/integration/reverse-proxy/index.md rename to content/en/developer/integration/reverse-proxy/index.md diff --git a/content/developer/integration/reverse-proxy/meta.json b/content/en/developer/integration/reverse-proxy/meta.json similarity index 100% rename from content/developer/integration/reverse-proxy/meta.json rename to content/en/developer/integration/reverse-proxy/meta.json diff --git a/content/developer/integration/reverse-proxy/nginx.md b/content/en/developer/integration/reverse-proxy/nginx.md similarity index 100% rename from content/developer/integration/reverse-proxy/nginx.md rename to content/en/developer/integration/reverse-proxy/nginx.md diff --git a/content/developer/integration/reverse-proxy/traefik.md b/content/en/developer/integration/reverse-proxy/traefik.md similarity index 100% rename from content/developer/integration/reverse-proxy/traefik.md rename to content/en/developer/integration/reverse-proxy/traefik.md diff --git a/content/developer/license.md b/content/en/developer/license.md similarity index 100% rename from content/developer/license.md rename to content/en/developer/license.md diff --git a/content/developer/mcp.md b/content/en/developer/mcp.md similarity index 100% rename from content/developer/mcp.md rename to content/en/developer/mcp.md diff --git a/content/developer/meta.json b/content/en/developer/meta.json similarity index 100% rename from content/developer/meta.json rename to content/en/developer/meta.json diff --git a/content/developer/sdk/go.md b/content/en/developer/sdk/go.md similarity index 100% rename from content/developer/sdk/go.md rename to content/en/developer/sdk/go.md diff --git a/content/developer/sdk/index.md b/content/en/developer/sdk/index.md similarity index 100% rename from content/developer/sdk/index.md rename to content/en/developer/sdk/index.md diff --git a/content/developer/sdk/java.md b/content/en/developer/sdk/java.md similarity index 100% rename from content/developer/sdk/java.md rename to content/en/developer/sdk/java.md diff --git a/content/developer/sdk/javascript.md b/content/en/developer/sdk/javascript.md similarity index 100% rename from content/developer/sdk/javascript.md rename to content/en/developer/sdk/javascript.md diff --git a/content/en/developer/sdk/meta.json b/content/en/developer/sdk/meta.json new file mode 100644 index 000000000..24708c5f0 --- /dev/null +++ b/content/en/developer/sdk/meta.json @@ -0,0 +1,12 @@ +{ + "title": "SDK", + "pages": [ + "[Java](/en/developer/sdk/java)", + "[Python](/en/developer/sdk/python)", + "[Rust](/en/developer/sdk/rust)", + "[JavaScript](/en/developer/sdk/javascript)", + "[TypeScript](/en/developer/sdk/typescript)", + "[Golang](/en/developer/sdk/go)", + "[Other SDKs](/en/developer/sdk/other)" + ] +} diff --git a/content/developer/sdk/other.md b/content/en/developer/sdk/other.md similarity index 100% rename from content/developer/sdk/other.md rename to content/en/developer/sdk/other.md diff --git a/content/developer/sdk/python.md b/content/en/developer/sdk/python.md similarity index 100% rename from content/developer/sdk/python.md rename to content/en/developer/sdk/python.md diff --git a/content/developer/sdk/rust.md b/content/en/developer/sdk/rust.md similarity index 100% rename from content/developer/sdk/rust.md rename to content/en/developer/sdk/rust.md diff --git a/content/developer/sdk/typescript.md b/content/en/developer/sdk/typescript.md similarity index 100% rename from content/developer/sdk/typescript.md rename to content/en/developer/sdk/typescript.md diff --git a/content/index.mdx b/content/en/index.mdx similarity index 84% rename from content/index.mdx rename to content/en/index.mdx index d9b0e2a3a..da087cfc6 100644 --- a/content/index.mdx +++ b/content/en/index.mdx @@ -10,14 +10,14 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows for S3-compatible workloads. This documentation covers installation, administration, security, and operations for RustFS clusters. - + Review installation requirements
- + Install on Linux @@ -26,7 +26,7 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows - + Install with Docker @@ -35,7 +35,7 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows - + Install with Podman @@ -44,7 +44,7 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows - + Install with Helm @@ -53,7 +53,7 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows - + Install with the Operator @@ -62,7 +62,7 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows - + Install on macOS @@ -71,7 +71,7 @@ description: "Install RustFS on Linux, containers, Kubernetes, macOS, or Windows - + Install on Windows diff --git a/content/installation/cloud-native/helm-chart/cert-manager.md b/content/en/installation/cloud-native/helm-chart/cert-manager.md similarity index 100% rename from content/installation/cloud-native/helm-chart/cert-manager.md rename to content/en/installation/cloud-native/helm-chart/cert-manager.md diff --git a/content/installation/cloud-native/helm-chart/index.md b/content/en/installation/cloud-native/helm-chart/index.md similarity index 94% rename from content/installation/cloud-native/helm-chart/index.md rename to content/en/installation/cloud-native/helm-chart/index.md index bc28bffe1..26652e5be 100644 --- a/content/installation/cloud-native/helm-chart/index.md +++ b/content/en/installation/cloud-native/helm-chart/index.md @@ -16,6 +16,6 @@ Use the Helm chart when you want Helm to manage one RustFS cluster. Use the [Rus ## Helm chart workflows -- [Install](./installation.md) covers requirements and standalone or distributed deployment. +- [Install](./installation.mdx) covers requirements and standalone or distributed deployment. - [mTLS](./mtls.md) encrypts and authenticates traffic between RustFS Pods. - [cert-manager](./cert-manager.md) issues and renews certificates for RustFS Ingress and mTLS. \ No newline at end of file diff --git a/content/installation/cloud-native/helm-chart/installation.mdx b/content/en/installation/cloud-native/helm-chart/installation.mdx similarity index 100% rename from content/installation/cloud-native/helm-chart/installation.mdx rename to content/en/installation/cloud-native/helm-chart/installation.mdx diff --git a/content/installation/cloud-native/helm-chart/meta.json b/content/en/installation/cloud-native/helm-chart/meta.json similarity index 100% rename from content/installation/cloud-native/helm-chart/meta.json rename to content/en/installation/cloud-native/helm-chart/meta.json diff --git a/content/installation/cloud-native/helm-chart/mtls.md b/content/en/installation/cloud-native/helm-chart/mtls.md similarity index 100% rename from content/installation/cloud-native/helm-chart/mtls.md rename to content/en/installation/cloud-native/helm-chart/mtls.md diff --git a/content/installation/cloud-native/index.md b/content/en/installation/cloud-native/index.md similarity index 100% rename from content/installation/cloud-native/index.md rename to content/en/installation/cloud-native/index.md diff --git a/content/installation/cloud-native/meta.json b/content/en/installation/cloud-native/meta.json similarity index 100% rename from content/installation/cloud-native/meta.json rename to content/en/installation/cloud-native/meta.json diff --git a/content/installation/cloud-native/operator/index.md b/content/en/installation/cloud-native/operator/index.md similarity index 100% rename from content/installation/cloud-native/operator/index.md rename to content/en/installation/cloud-native/operator/index.md diff --git a/content/installation/cloud-native/operator/installation.md b/content/en/installation/cloud-native/operator/installation.md similarity index 100% rename from content/installation/cloud-native/operator/installation.md rename to content/en/installation/cloud-native/operator/installation.md diff --git a/content/installation/cloud-native/operator/kms.md b/content/en/installation/cloud-native/operator/kms.md similarity index 100% rename from content/installation/cloud-native/operator/kms.md rename to content/en/installation/cloud-native/operator/kms.md diff --git a/content/installation/cloud-native/operator/meta.json b/content/en/installation/cloud-native/operator/meta.json similarity index 100% rename from content/installation/cloud-native/operator/meta.json rename to content/en/installation/cloud-native/operator/meta.json diff --git a/content/installation/cloud-native/operator/pool-expansion.md b/content/en/installation/cloud-native/operator/pool-expansion.md similarity index 100% rename from content/installation/cloud-native/operator/pool-expansion.md rename to content/en/installation/cloud-native/operator/pool-expansion.md diff --git a/content/installation/cloud-native/operator/tenant.md b/content/en/installation/cloud-native/operator/tenant.md similarity index 100% rename from content/installation/cloud-native/operator/tenant.md rename to content/en/installation/cloud-native/operator/tenant.md diff --git a/content/installation/container/docker.md b/content/en/installation/container/docker.md similarity index 100% rename from content/installation/container/docker.md rename to content/en/installation/container/docker.md diff --git a/content/installation/container/index.mdx b/content/en/installation/container/index.mdx similarity index 100% rename from content/installation/container/index.mdx rename to content/en/installation/container/index.mdx diff --git a/content/installation/container/meta.json b/content/en/installation/container/meta.json similarity index 100% rename from content/installation/container/meta.json rename to content/en/installation/container/meta.json diff --git a/content/installation/container/podman.md b/content/en/installation/container/podman.md similarity index 100% rename from content/installation/container/podman.md rename to content/en/installation/container/podman.md diff --git a/content/installation/index.md b/content/en/installation/index.md similarity index 100% rename from content/installation/index.md rename to content/en/installation/index.md diff --git a/content/installation/linux/images/console.jpg b/content/en/installation/linux/images/console.jpg similarity index 100% rename from content/installation/linux/images/console.jpg rename to content/en/installation/linux/images/console.jpg diff --git a/content/installation/linux/index.md b/content/en/installation/linux/index.md similarity index 100% rename from content/installation/linux/index.md rename to content/en/installation/linux/index.md diff --git a/content/en/installation/linux/meta.json b/content/en/installation/linux/meta.json new file mode 100644 index 000000000..0dcea19dd --- /dev/null +++ b/content/en/installation/linux/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Linux", + "pages": [ + "[Quick Start](/en/installation/linux/quick-start)", + "[Prerequisites & Service Setup](/en/installation/linux/prerequisites-and-service)", + "[Single Node Single Disk (SNSD)](/en/installation/linux/single-node-single-disk)", + "[Single Node Multiple Disk (SNMD)](/en/installation/linux/single-node-multiple-disk)", + "[Multiple Node Multiple Disk (MNMD)](/en/installation/linux/multiple-node-multiple-disk)" + ] +} diff --git a/content/installation/linux/multiple-node-multiple-disk.md b/content/en/installation/linux/multiple-node-multiple-disk.md similarity index 100% rename from content/installation/linux/multiple-node-multiple-disk.md rename to content/en/installation/linux/multiple-node-multiple-disk.md diff --git a/content/installation/linux/prerequisites-and-service.md b/content/en/installation/linux/prerequisites-and-service.md similarity index 100% rename from content/installation/linux/prerequisites-and-service.md rename to content/en/installation/linux/prerequisites-and-service.md diff --git a/content/installation/linux/quick-start.md b/content/en/installation/linux/quick-start.md similarity index 100% rename from content/installation/linux/quick-start.md rename to content/en/installation/linux/quick-start.md diff --git a/content/installation/linux/single-node-multiple-disk.md b/content/en/installation/linux/single-node-multiple-disk.md similarity index 100% rename from content/installation/linux/single-node-multiple-disk.md rename to content/en/installation/linux/single-node-multiple-disk.md diff --git a/content/installation/linux/single-node-single-disk.md b/content/en/installation/linux/single-node-single-disk.md similarity index 100% rename from content/installation/linux/single-node-single-disk.md rename to content/en/installation/linux/single-node-single-disk.md diff --git a/content/installation/macos/images/macos-setup.jpg b/content/en/installation/macos/images/macos-setup.jpg similarity index 100% rename from content/installation/macos/images/macos-setup.jpg rename to content/en/installation/macos/images/macos-setup.jpg diff --git a/content/installation/macos/images/setting.jpg b/content/en/installation/macos/images/setting.jpg similarity index 100% rename from content/installation/macos/images/setting.jpg rename to content/en/installation/macos/images/setting.jpg diff --git a/content/installation/macos/index.md b/content/en/installation/macos/index.md similarity index 100% rename from content/installation/macos/index.md rename to content/en/installation/macos/index.md diff --git a/content/installation/meta.json b/content/en/installation/meta.json similarity index 63% rename from content/installation/meta.json rename to content/en/installation/meta.json index bbb7164e7..50e6f7c52 100644 --- a/content/installation/meta.json +++ b/content/en/installation/meta.json @@ -6,7 +6,7 @@ "linux", "container", "cloud-native", - "[Windows](/installation/windows)", - "[macOS](/installation/macos)" + "[Windows](/en/installation/windows)", + "[macOS](/en/installation/macos)" ] } \ No newline at end of file diff --git a/content/installation/requirement/checklists/hardware-checklists.md b/content/en/installation/requirement/checklists/hardware-checklists.md similarity index 100% rename from content/installation/requirement/checklists/hardware-checklists.md rename to content/en/installation/requirement/checklists/hardware-checklists.md diff --git a/content/installation/requirement/checklists/hardware-selection.md b/content/en/installation/requirement/checklists/hardware-selection.md similarity index 100% rename from content/installation/requirement/checklists/hardware-selection.md rename to content/en/installation/requirement/checklists/hardware-selection.md diff --git a/content/installation/requirement/checklists/index.md b/content/en/installation/requirement/checklists/index.md similarity index 100% rename from content/installation/requirement/checklists/index.md rename to content/en/installation/requirement/checklists/index.md diff --git a/content/en/installation/requirement/checklists/meta.json b/content/en/installation/requirement/checklists/meta.json new file mode 100644 index 000000000..598c9f25f --- /dev/null +++ b/content/en/installation/requirement/checklists/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Checklist", + "pages": [ + "[Hardware Checklist](/en/installation/requirement/checklists/hardware-checklists)", + "[Hardware Selection](/en/installation/requirement/checklists/hardware-selection)", + "[Network Checklist](/en/installation/requirement/checklists/network-checklists)", + "[Software Checklist](/en/installation/requirement/checklists/software-checklists)", + "[Security Checklist](/en/installation/requirement/checklists/security-checklists)" + ] +} diff --git a/content/installation/requirement/checklists/network-checklists.md b/content/en/installation/requirement/checklists/network-checklists.md similarity index 100% rename from content/installation/requirement/checklists/network-checklists.md rename to content/en/installation/requirement/checklists/network-checklists.md diff --git a/content/installation/requirement/checklists/security-checklists.md b/content/en/installation/requirement/checklists/security-checklists.md similarity index 100% rename from content/installation/requirement/checklists/security-checklists.md rename to content/en/installation/requirement/checklists/security-checklists.md diff --git a/content/installation/requirement/checklists/software-checklists.md b/content/en/installation/requirement/checklists/software-checklists.md similarity index 100% rename from content/installation/requirement/checklists/software-checklists.md rename to content/en/installation/requirement/checklists/software-checklists.md diff --git a/content/installation/requirement/disk-preparation.md b/content/en/installation/requirement/disk-preparation.md similarity index 100% rename from content/installation/requirement/disk-preparation.md rename to content/en/installation/requirement/disk-preparation.md diff --git a/content/installation/requirement/ec-configuration.md b/content/en/installation/requirement/ec-configuration.md similarity index 100% rename from content/installation/requirement/ec-configuration.md rename to content/en/installation/requirement/ec-configuration.md diff --git a/content/installation/requirement/meta.json b/content/en/installation/requirement/meta.json similarity index 60% rename from content/installation/requirement/meta.json rename to content/en/installation/requirement/meta.json index 6538db301..b1153db04 100644 --- a/content/installation/requirement/meta.json +++ b/content/en/installation/requirement/meta.json @@ -1,7 +1,7 @@ { "title": "Requirement", "pages": [ - "[Topology Selection](/installation#deployment-mode-comparison)", + "[Topology Selection](/en/installation#deployment-mode-comparison)", "ec-configuration", "disk-preparation", "checklists" diff --git a/content/installation/windows/images/rustfs-console-login.png b/content/en/installation/windows/images/rustfs-console-login.png similarity index 100% rename from content/installation/windows/images/rustfs-console-login.png rename to content/en/installation/windows/images/rustfs-console-login.png diff --git a/content/installation/windows/images/setting.jpg b/content/en/installation/windows/images/setting.jpg similarity index 100% rename from content/installation/windows/images/setting.jpg rename to content/en/installation/windows/images/setting.jpg diff --git a/content/installation/windows/images/windows-rustfs-launcher.jpg b/content/en/installation/windows/images/windows-rustfs-launcher.jpg similarity index 100% rename from content/installation/windows/images/windows-rustfs-launcher.jpg rename to content/en/installation/windows/images/windows-rustfs-launcher.jpg diff --git a/content/installation/windows/images/windows-setup.jpg b/content/en/installation/windows/images/windows-setup.jpg similarity index 100% rename from content/installation/windows/images/windows-setup.jpg rename to content/en/installation/windows/images/windows-setup.jpg diff --git a/content/installation/windows/index.md b/content/en/installation/windows/index.md similarity index 100% rename from content/installation/windows/index.md rename to content/en/installation/windows/index.md diff --git a/content/integration/tls-configured.md b/content/en/integration/tls-configured.md similarity index 100% rename from content/integration/tls-configured.md rename to content/en/integration/tls-configured.md diff --git a/content/integration/virtual.md b/content/en/integration/virtual.md similarity index 100% rename from content/integration/virtual.md rename to content/en/integration/virtual.md diff --git a/content/meta.json b/content/en/meta.json similarity index 100% rename from content/meta.json rename to content/en/meta.json diff --git a/content/operations/credentials.md b/content/en/operations/credentials.md similarity index 100% rename from content/operations/credentials.md rename to content/en/operations/credentials.md diff --git a/content/operations/event-notifications.md b/content/en/operations/event-notifications.md similarity index 100% rename from content/operations/event-notifications.md rename to content/en/operations/event-notifications.md diff --git a/content/operations/high-availability/index.md b/content/en/operations/high-availability/index.md similarity index 100% rename from content/operations/high-availability/index.md rename to content/en/operations/high-availability/index.md diff --git a/content/operations/high-availability/meta.json b/content/en/operations/high-availability/meta.json similarity index 100% rename from content/operations/high-availability/meta.json rename to content/en/operations/high-availability/meta.json diff --git a/content/operations/high-availability/node-healing.md b/content/en/operations/high-availability/node-healing.md similarity index 100% rename from content/operations/high-availability/node-healing.md rename to content/en/operations/high-availability/node-healing.md diff --git a/content/operations/high-availability/site-replication.md b/content/en/operations/high-availability/site-replication.md similarity index 100% rename from content/operations/high-availability/site-replication.md rename to content/en/operations/high-availability/site-replication.md diff --git a/content/operations/index.md b/content/en/operations/index.md similarity index 100% rename from content/operations/index.md rename to content/en/operations/index.md diff --git a/content/operations/meta.json b/content/en/operations/meta.json similarity index 100% rename from content/operations/meta.json rename to content/en/operations/meta.json diff --git a/content/operations/observability.md b/content/en/operations/observability.md similarity index 100% rename from content/operations/observability.md rename to content/en/operations/observability.md diff --git a/content/operations/rc.mdx b/content/en/operations/rc.mdx similarity index 100% rename from content/operations/rc.mdx rename to content/en/operations/rc.mdx diff --git a/content/operations/scaling/data-rebalancing.md b/content/en/operations/scaling/data-rebalancing.md similarity index 100% rename from content/operations/scaling/data-rebalancing.md rename to content/en/operations/scaling/data-rebalancing.md diff --git a/content/operations/scaling/images/pool-decommission-completed-console.png b/content/en/operations/scaling/images/pool-decommission-completed-console.png similarity index 100% rename from content/operations/scaling/images/pool-decommission-completed-console.png rename to content/en/operations/scaling/images/pool-decommission-completed-console.png diff --git a/content/operations/scaling/images/pool-decommission-confirmation-console.png b/content/en/operations/scaling/images/pool-decommission-confirmation-console.png similarity index 100% rename from content/operations/scaling/images/pool-decommission-confirmation-console.png rename to content/en/operations/scaling/images/pool-decommission-confirmation-console.png diff --git a/content/operations/scaling/images/pool-decommission-final-topology-console.png b/content/en/operations/scaling/images/pool-decommission-final-topology-console.png similarity index 100% rename from content/operations/scaling/images/pool-decommission-final-topology-console.png rename to content/en/operations/scaling/images/pool-decommission-final-topology-console.png diff --git a/content/operations/scaling/images/pool-decommission-running-console.png b/content/en/operations/scaling/images/pool-decommission-running-console.png similarity index 100% rename from content/operations/scaling/images/pool-decommission-running-console.png rename to content/en/operations/scaling/images/pool-decommission-running-console.png diff --git a/content/operations/scaling/images/pool-decommission-selection-console.png b/content/en/operations/scaling/images/pool-decommission-selection-console.png similarity index 100% rename from content/operations/scaling/images/pool-decommission-selection-console.png rename to content/en/operations/scaling/images/pool-decommission-selection-console.png diff --git a/content/operations/scaling/images/pool-expansion-console.png b/content/en/operations/scaling/images/pool-expansion-console.png similarity index 100% rename from content/operations/scaling/images/pool-expansion-console.png rename to content/en/operations/scaling/images/pool-expansion-console.png diff --git a/content/operations/scaling/images/rebalance-completed-console.png b/content/en/operations/scaling/images/rebalance-completed-console.png similarity index 100% rename from content/operations/scaling/images/rebalance-completed-console.png rename to content/en/operations/scaling/images/rebalance-completed-console.png diff --git a/content/operations/scaling/images/rebalance-running-console.png b/content/en/operations/scaling/images/rebalance-running-console.png similarity index 100% rename from content/operations/scaling/images/rebalance-running-console.png rename to content/en/operations/scaling/images/rebalance-running-console.png diff --git a/content/operations/scaling/index.md b/content/en/operations/scaling/index.md similarity index 100% rename from content/operations/scaling/index.md rename to content/en/operations/scaling/index.md diff --git a/content/operations/scaling/meta.json b/content/en/operations/scaling/meta.json similarity index 100% rename from content/operations/scaling/meta.json rename to content/en/operations/scaling/meta.json diff --git a/content/operations/scaling/storage-pool-decommission.md b/content/en/operations/scaling/storage-pool-decommission.md similarity index 100% rename from content/operations/scaling/storage-pool-decommission.md rename to content/en/operations/scaling/storage-pool-decommission.md diff --git a/content/operations/scaling/storage-pool-expansion.md b/content/en/operations/scaling/storage-pool-expansion.md similarity index 100% rename from content/operations/scaling/storage-pool-expansion.md rename to content/en/operations/scaling/storage-pool-expansion.md diff --git a/content/operations/status-check.md b/content/en/operations/status-check.md similarity index 100% rename from content/operations/status-check.md rename to content/en/operations/status-check.md diff --git a/content/operations/upgrade/binary/index.md b/content/en/operations/upgrade/binary/index.md similarity index 100% rename from content/operations/upgrade/binary/index.md rename to content/en/operations/upgrade/binary/index.md diff --git a/content/operations/upgrade/container/index.md b/content/en/operations/upgrade/container/index.md similarity index 100% rename from content/operations/upgrade/container/index.md rename to content/en/operations/upgrade/container/index.md diff --git a/content/operations/upgrade/index.md b/content/en/operations/upgrade/index.md similarity index 100% rename from content/operations/upgrade/index.md rename to content/en/operations/upgrade/index.md diff --git a/content/operations/upgrade/kubernetes/index.md b/content/en/operations/upgrade/kubernetes/index.md similarity index 100% rename from content/operations/upgrade/kubernetes/index.md rename to content/en/operations/upgrade/kubernetes/index.md diff --git a/content/en/operations/upgrade/meta.json b/content/en/operations/upgrade/meta.json new file mode 100644 index 000000000..5b2f5c6b5 --- /dev/null +++ b/content/en/operations/upgrade/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Upgrade", + "pages": [ + "[Binary](/en/operations/upgrade/binary)", + "[Container](/en/operations/upgrade/container)", + "[Kubernetes](/en/operations/upgrade/kubernetes)" + ] +} \ No newline at end of file diff --git a/content/reference/cli.md b/content/en/reference/cli.md similarity index 100% rename from content/reference/cli.md rename to content/en/reference/cli.md diff --git a/content/reference/environment-variables.md b/content/en/reference/environment-variables.md similarity index 100% rename from content/reference/environment-variables.md rename to content/en/reference/environment-variables.md diff --git a/content/reference/index.md b/content/en/reference/index.md similarity index 100% rename from content/reference/index.md rename to content/en/reference/index.md diff --git a/content/reference/meta.json b/content/en/reference/meta.json similarity index 100% rename from content/reference/meta.json rename to content/en/reference/meta.json diff --git a/content/security-compliance/audit-logs.md b/content/en/security-compliance/audit-logs.md similarity index 100% rename from content/security-compliance/audit-logs.md rename to content/en/security-compliance/audit-logs.md diff --git a/content/security-compliance/encryption/index.md b/content/en/security-compliance/encryption/index.md similarity index 100% rename from content/security-compliance/encryption/index.md rename to content/en/security-compliance/encryption/index.md diff --git a/content/security-compliance/encryption/kms.md b/content/en/security-compliance/encryption/kms.md similarity index 100% rename from content/security-compliance/encryption/kms.md rename to content/en/security-compliance/encryption/kms.md diff --git a/content/security-compliance/encryption/meta.json b/content/en/security-compliance/encryption/meta.json similarity index 100% rename from content/security-compliance/encryption/meta.json rename to content/en/security-compliance/encryption/meta.json diff --git a/content/security-compliance/encryption/sse-c.md b/content/en/security-compliance/encryption/sse-c.md similarity index 100% rename from content/security-compliance/encryption/sse-c.md rename to content/en/security-compliance/encryption/sse-c.md diff --git a/content/security-compliance/encryption/sse-s.md b/content/en/security-compliance/encryption/sse-s.md similarity index 100% rename from content/security-compliance/encryption/sse-s.md rename to content/en/security-compliance/encryption/sse-s.md diff --git a/content/security-compliance/iam/access-token.md b/content/en/security-compliance/iam/access-token.md similarity index 100% rename from content/security-compliance/iam/access-token.md rename to content/en/security-compliance/iam/access-token.md diff --git a/content/security-compliance/iam/images/access_token_creation.png b/content/en/security-compliance/iam/images/access_token_creation.png similarity index 100% rename from content/security-compliance/iam/images/access_token_creation.png rename to content/en/security-compliance/iam/images/access_token_creation.png diff --git a/content/security-compliance/iam/images/access_token_deletion.png b/content/en/security-compliance/iam/images/access_token_deletion.png similarity index 100% rename from content/security-compliance/iam/images/access_token_deletion.png rename to content/en/security-compliance/iam/images/access_token_deletion.png diff --git a/content/security-compliance/iam/index.md b/content/en/security-compliance/iam/index.md similarity index 100% rename from content/security-compliance/iam/index.md rename to content/en/security-compliance/iam/index.md diff --git a/content/en/security-compliance/iam/meta.json b/content/en/security-compliance/iam/meta.json new file mode 100644 index 000000000..d7233614d --- /dev/null +++ b/content/en/security-compliance/iam/meta.json @@ -0,0 +1,8 @@ +{ + "title": "IAM", + "pages": [ + "[Users, Groups, and Policies](/en/security-compliance/iam/policies)", + "[Service Accounts and STS](/en/security-compliance/iam/sts)", + "[Access Keys](/en/security-compliance/iam/access-token)" + ] +} diff --git a/content/security-compliance/iam/policies.md b/content/en/security-compliance/iam/policies.md similarity index 100% rename from content/security-compliance/iam/policies.md rename to content/en/security-compliance/iam/policies.md diff --git a/content/security-compliance/iam/sts.md b/content/en/security-compliance/iam/sts.md similarity index 100% rename from content/security-compliance/iam/sts.md rename to content/en/security-compliance/iam/sts.md diff --git a/content/security-compliance/index.md b/content/en/security-compliance/index.md similarity index 100% rename from content/security-compliance/index.md rename to content/en/security-compliance/index.md diff --git a/content/security-compliance/meta.json b/content/en/security-compliance/meta.json similarity index 54% rename from content/security-compliance/meta.json rename to content/en/security-compliance/meta.json index e2c7ad17e..838473143 100644 --- a/content/security-compliance/meta.json +++ b/content/en/security-compliance/meta.json @@ -5,8 +5,8 @@ "iam", "encryption", "oidc", - "[TLS Configuration](/integration/tls-configured)", + "[TLS Configuration](/en/integration/tls-configured)", "audit-logs", - "[Credential Management](/operations/credentials)" + "[Credential Management](/en/operations/credentials)" ] } diff --git a/content/security-compliance/oidc/index.md b/content/en/security-compliance/oidc/index.md similarity index 100% rename from content/security-compliance/oidc/index.md rename to content/en/security-compliance/oidc/index.md diff --git a/content/security-compliance/oidc/keycloak.md b/content/en/security-compliance/oidc/keycloak.md similarity index 100% rename from content/security-compliance/oidc/keycloak.md rename to content/en/security-compliance/oidc/keycloak.md diff --git a/content/security-compliance/oidc/meta.json b/content/en/security-compliance/oidc/meta.json similarity index 100% rename from content/security-compliance/oidc/meta.json rename to content/en/security-compliance/oidc/meta.json diff --git a/content/troubleshooting/driver.md b/content/en/troubleshooting/driver.md similarity index 100% rename from content/troubleshooting/driver.md rename to content/en/troubleshooting/driver.md diff --git a/content/troubleshooting/index.md b/content/en/troubleshooting/index.md similarity index 100% rename from content/troubleshooting/index.md rename to content/en/troubleshooting/index.md diff --git a/content/troubleshooting/meta.json b/content/en/troubleshooting/meta.json similarity index 100% rename from content/troubleshooting/meta.json rename to content/en/troubleshooting/meta.json diff --git a/content/troubleshooting/node.md b/content/en/troubleshooting/node.md similarity index 100% rename from content/troubleshooting/node.md rename to content/en/troubleshooting/node.md diff --git a/content/installation/linux/meta.json b/content/installation/linux/meta.json deleted file mode 100644 index 4a22b48e9..000000000 --- a/content/installation/linux/meta.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "Linux", - "pages": [ - "[Quick Start](/installation/linux/quick-start)", - "[Prerequisites & Service Setup](/installation/linux/prerequisites-and-service)", - "[Single Node Single Disk (SNSD)](/installation/linux/single-node-single-disk)", - "[Single Node Multiple Disk (SNMD)](/installation/linux/single-node-multiple-disk)", - "[Multiple Node Multiple Disk (MNMD)](/installation/linux/multiple-node-multiple-disk)" - ] -} diff --git a/content/installation/requirement/checklists/meta.json b/content/installation/requirement/checklists/meta.json deleted file mode 100644 index 1fd22fd68..000000000 --- a/content/installation/requirement/checklists/meta.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "Checklist", - "pages": [ - "[Hardware Checklist](/installation/requirement/checklists/hardware-checklists)", - "[Hardware Selection](/installation/requirement/checklists/hardware-selection)", - "[Network Checklist](/installation/requirement/checklists/network-checklists)", - "[Software Checklist](/installation/requirement/checklists/software-checklists)", - "[Security Checklist](/installation/requirement/checklists/security-checklists)" - ] -} diff --git a/content/operations/upgrade/meta.json b/content/operations/upgrade/meta.json deleted file mode 100644 index e7d35086d..000000000 --- a/content/operations/upgrade/meta.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "title": "Upgrade", - "pages": [ - "[Binary](/operations/upgrade/binary)", - "[Container](/operations/upgrade/container)", - "[Kubernetes](/operations/upgrade/kubernetes)" - ] -} \ No newline at end of file diff --git a/content/security-compliance/iam/meta.json b/content/security-compliance/iam/meta.json deleted file mode 100644 index 451db04e3..000000000 --- a/content/security-compliance/iam/meta.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "title": "IAM", - "pages": [ - "[Users, Groups, and Policies](/security-compliance/iam/policies)", - "[Service Accounts and STS](/security-compliance/iam/sts)", - "[Access Keys](/security-compliance/iam/access-token)" - ] -} diff --git a/content/zh/administration/console/images/rustfs-console-login.png b/content/zh/administration/console/images/rustfs-console-login.png new file mode 100644 index 000000000..6282809df Binary files /dev/null and b/content/zh/administration/console/images/rustfs-console-login.png differ diff --git a/content/zh/administration/console/index.md b/content/zh/administration/console/index.md new file mode 100644 index 000000000..bd6877050 --- /dev/null +++ b/content/zh/administration/console/index.md @@ -0,0 +1,69 @@ +--- +title: "控制台" +description: "启用 RustFS 控制台,将其连接到服务器并安全登录。" +--- + +**RustFS 控制台**是 RustFS 的 Web 管理界面。使用本页可启用控制台、打开登录页面并选择合适的登录方式。存储桶、对象和身份管理的详细操作请参阅各自的文档章节。 + +## 启用控制台 + +控制台默认启用并监听端口 `9001`,与端口 `9000` 上的 S3 API 分开。你可以使用以下环境变量显式设置其行为: + +```ini title="/etc/default/rustfs" +RUSTFS_CONSOLE_ENABLE=true +RUSTFS_CONSOLE_ADDRESS=":9001" +``` + +更改这些值后请重启 RustFS。如果不应运行控制台,请设置 `RUSTFS_CONSOLE_ENABLE=false`。 + +对应的命令行选项是 `--console-enable` 和 `--console-address`。完整的服务器配置请参阅 [CLI 参考](/reference/cli)和[环境变量参考](/reference/environment-variables)。 + +## 打开控制台 + +打开以下地址,并将 `` 替换为 RustFS 服务器地址: + +```text +http://:9001 +``` + +![提供密钥、STS 和 OIDC 登录选项的 RustFS 控制台登录页面](./images/rustfs-console-login.png) + +本地部署请使用 `http://localhost:9001`。Windows 和 macOS 桌面启动器改用端口 `7001`。 + +如果登录页面无法连接目标 RustFS 服务,请选择 **Server Configuration** 或打开 `/config`。输入可从外部访问的 RustFS 服务地址,并在健康检查成功后保存。**Reset** 会清除已保存的地址;**Skip** 会返回登录页面且不作更改。 + +## 登录 + +显示的登录方式取决于部署配置: + +- **Key Login** 使用为 RustFS 部署配置的访问密钥和秘密密钥。这是本地管理员的标准登录方式。 +- **STS Login** 使用临时安全令牌服务(Security Token Service,STS)凭证。仅当身份工作流已签发有效会话令牌时使用。 +- 配置 OpenID Connect(OIDC)提供商后会显示 **OIDC Login**。选择提供商,并通过身份提供商完成身份验证。 + +登录后,控制台会打开账户有权访问的第一个页面。菜单和操作因账户策略及已启用的平台功能而异;缺少某个菜单不一定表示控制台出错。 + +如果登录失败,请先检查所选登录方式、凭证、目标服务器地址和账户状态,再重试。 + +:::warning[不要暴露默认凭证] + +未配置自定义凭证时,RustFS 会回退到 `rustfsadmin` / `rustfsadmin`。仅在一次性本地测试中使用这些默认值。在允许其他用户访问控制台前,请配置唯一的访问密钥和高强度秘密密钥。 + +::: + +## 运维注意事项 + +- 在可信网络之外开放控制台前,请使用 [TLS](/integration/tls-configured)。 +- 限制对控制台监听器的网络访问,仅在需要跨源访问时配置[控制台 CORS](/administration/cors)。 +- 控制台会话继承已登录身份的权限。日常操作请使用最小权限账户。 +- 退出登录或会话过期后会返回登录页面。不要在共享浏览器中保存管理员凭证。 + +## 管理工作流 + +- [创建和管理存储桶](/administration/data/bucket/creation) +- [上传和管理对象](/administration/data/object/creation) +- [管理访问密钥](/security-compliance/iam/access-token) +- [配置身份与访问管理](/security-compliance/iam) + +## 后续步骤 + +在可信网络之外开放控制台前,请查看[安全检查清单](/installation/requirement/checklists/security-checklists)。如需使用 OIDC 登录,请继续阅读 [OIDC 配置指南](/security-compliance/oidc)。 \ No newline at end of file diff --git a/content/zh/administration/cors/index.md b/content/zh/administration/cors/index.md new file mode 100644 index 000000000..ded1a6eae --- /dev/null +++ b/content/zh/administration/cors/index.md @@ -0,0 +1,50 @@ +--- +title: "CORS 配置" +description: "为 RustFS S3 API 和控制台配置允许的浏览器来源。" +--- + +跨源资源共享(Cross-Origin Resource Sharing,CORS)控制哪些浏览器来源可以访问 RustFS S3 API 和控制台。请分别配置每个监听器,然后重启 RustFS 以应用环境变量更改。 + +## S3 API 来源 + +将 `RUSTFS_CORS_ALLOWED_ORIGINS` 设置为以逗号分隔的可信来源列表: + +```ini title="/etc/default/rustfs" +RUSTFS_CORS_ALLOWED_ORIGINS="https://app.example.com,https://admin.example.com" +``` + +未设置此变量或变量为空时,S3 端点不会添加通用 CORS 响应头。显式来源列表允许来自匹配来源且携带凭证的浏览器请求。 + +可以将该值设置为 `*`,以允许来自任何来源的请求。通配符模式不允许浏览器携带凭证。 + +:::warning[生产环境请使用显式来源] + +对于发送凭证的应用,请使用以逗号分隔的允许列表。仅对不需要浏览器携带凭证请求的公共资源使用 `*`。 + +::: + +## 控制台来源 + +控制台使用单独的变量: + +```ini title="/etc/default/rustfs" +RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS="https://admin.example.com" +``` + +如果多个浏览器来源需要访问控制台,请使用以逗号分隔的列表。仅在必须允许任何来源时设置 `*`。 + +## 验证响应 + +发送带有 `Origin` 请求头的请求,并检查 CORS 响应头: + +```bash +curl -i \ + -H "Origin: https://app.example.com" \ + http://localhost:9000/ +``` + +确认 `Access-Control-Allow-Origin` 包含预期来源。使用未列出的来源重复检查,并确认该来源未获允许。 + +## 后续步骤 + +有关已验证的默认值和配置格式,请参阅[环境变量参考](/reference/environment-variables#cors)。 \ No newline at end of file diff --git a/content/zh/administration/data/bucket/creation.md b/content/zh/administration/data/bucket/creation.md new file mode 100644 index 000000000..635454727 --- /dev/null +++ b/content/zh/administration/data/bucket/creation.md @@ -0,0 +1,52 @@ +--- +title: "创建 RustFS 存储桶" +description: "使用 RustFS UI、rc 或 S3 API 创建存储桶。" +--- + +本指南介绍如何使用 RustFS UI、`rc` 或 S3 API 创建存储桶。 + +## 要求 + +- 正在运行的 RustFS 实例(参阅[安装指南](../../../installation/index.md))。 +- 已安装 [`rc`](/operations/rc),并为命令行工作流配置了别名。 + +## 使用 RustFS UI + +1. 登录 RustFS 控制台。 +2. 在存储桶页面右上角,选择 **Create Bucket**。 +3. 输入存储桶名称,然后单击 **Create** 完成创建。 + +![创建存储桶](images/bucket-creation-by-ui.png) + +## 使用 `rc` + +有关安装和别名配置,请参阅 [`rc` 指南](/operations/rc)。 + +创建存储桶: + +```bash +rc bucket create rustfs/my-bucket +rc bucket list rustfs/ +``` + +```text +✓ Bucket 'rustfs/my-bucket' created successfully. +``` + +## 使用 API + +通过 API 创建存储桶: + +```http +PUT /{bucketName} HTTP/1.1 +``` + +S3 请求必须使用 AWS Signature V4 签名,因此请使用 S3 客户端,不要手动构造请求头。为访问密钥配置 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 后,运行: + +```bash +aws s3api create-bucket \ + --bucket bucket-creation-by-api \ + --endpoint-url http://localhost:9000 +``` + +在 RustFS 控制台中确认存储桶已创建。 \ No newline at end of file diff --git a/content/zh/administration/data/bucket/deletion.md b/content/zh/administration/data/bucket/deletion.md new file mode 100644 index 000000000..b7b105ef3 --- /dev/null +++ b/content/zh/administration/data/bucket/deletion.md @@ -0,0 +1,54 @@ +--- +title: "删除 RustFS 存储桶" +description: "使用 RustFS UI、rc 或 S3 API 删除存储桶。" +--- + +本指南介绍如何使用 RustFS UI、`rc` 或 S3 API 删除存储桶。 + +## 要求 + +- 使用命令行工作流前,请安装并配置 [`rc`](/operations/rc)。 +- 删除目标存储桶前先将其清空;仅在检查将被删除的对象后使用 `--force`。 + +**警告**:删除存储桶无法撤销,并可能导致依赖该存储桶的应用中断。继续操作前,请确保已备份所有必要数据。 + +## 使用 RustFS UI + +1. 登录 RustFS 控制台。 +2. 在首页选择要删除的存储桶。 +3. 在最右侧选择 **Delete** 按钮。 +4. 在弹出对话框中单击 **Confirm**,完成存储桶删除。 + +![删除存储桶](images/bucket-deletion-on-ui.png) + +## 使用 `rc` + +有关安装和别名配置,请参阅 [`rc` 指南](/operations/rc)。 + +删除存储桶: + +```bash +rc bucket remove rustfs/my-bucket +``` + +```text +✓ Bucket 'rustfs/my-bucket' removed successfully. +``` + +## 使用 API + +通过 API 删除存储桶: + +```http +DELETE /{bucketName} HTTP/1.1 +``` + +S3 请求必须使用 AWS Signature V4 签名,因此请使用 S3 客户端,不要手动构造请求头。为访问密钥配置 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 后,运行: + +```bash +aws s3api delete-bucket \ + --bucket bucket-creation-by-api \ + --endpoint-url http://localhost:9000 +``` + +在 RustFS 控制台中确认存储桶已删除。 \ No newline at end of file diff --git a/content/zh/administration/data/bucket/images/bucket-creation-by-ui.png b/content/zh/administration/data/bucket/images/bucket-creation-by-ui.png new file mode 100644 index 000000000..c3415a5a9 Binary files /dev/null and b/content/zh/administration/data/bucket/images/bucket-creation-by-ui.png differ diff --git a/content/zh/administration/data/bucket/images/bucket-deletion-on-ui.png b/content/zh/administration/data/bucket/images/bucket-deletion-on-ui.png new file mode 100644 index 000000000..489b32375 Binary files /dev/null and b/content/zh/administration/data/bucket/images/bucket-deletion-on-ui.png differ diff --git a/content/zh/administration/data/bucket/images/bucket-quota-console.png b/content/zh/administration/data/bucket/images/bucket-quota-console.png new file mode 100644 index 000000000..5e46df451 Binary files /dev/null and b/content/zh/administration/data/bucket/images/bucket-quota-console.png differ diff --git a/content/zh/administration/data/bucket/meta.json b/content/zh/administration/data/bucket/meta.json new file mode 100644 index 000000000..00af9f84e --- /dev/null +++ b/content/zh/administration/data/bucket/meta.json @@ -0,0 +1,10 @@ +{ + "title": "存储桶", + "pages": [ + "creation", + "deletion", + "quota", + "replication", + "policy" + ] +} \ No newline at end of file diff --git a/content/zh/administration/data/bucket/policy.md b/content/zh/administration/data/bucket/policy.md new file mode 100644 index 000000000..56893d935 --- /dev/null +++ b/content/zh/administration/data/bucket/policy.md @@ -0,0 +1,205 @@ +--- +title: "存储桶策略" +description: "使用 S3 API 创建、应用、检查和验证 RustFS 存储桶策略。" +--- + +RustFS 存储桶策略是直接附加到存储桶的 S3 兼容资源策略。使用它们可允许或拒绝访问存储桶及其中的对象,包括为公开下载提供受控的匿名访问。 + +## 概述 + +存储桶策略包含一条或多条语句,用于匹配主体、操作、资源和可选条件。RustFS 在允许存储操作前,会针对存储桶请求评估该策略。 + +存储桶策略和 IAM 策略的用途不同: + +| 策略类型 | 附加到 | 常见用途 | +| --- | --- | --- | +| 存储桶策略 | 存储桶 | 授予公共访问权限、添加资源级限制,或授权访问某个存储桶。 | +| IAM 策略 | 用户或组 | 定义已验证身份可对一个或多个资源执行的操作。 | + +显式 `Deny` 优先于 `Allow`。存储桶所有者仍可获取、替换或删除存储桶策略,避免拒绝语句永久锁定策略管理。 + +RustFS 实现标准 S3 操作 `PutBucketPolicy`、`GetBucketPolicy`、`GetBucketPolicyStatus` 和 `DeleteBucketPolicy`。 + +:::warning[公共策略] + +包含 `"Principal": "*"` 的语句可授予无需身份验证的访问权限。请尽可能缩小操作和资源范围,并在生产环境使用策略前以匿名方式验证结果。 + +::: + +## 配置 + +### 要求 + +- 应用策略前先创建目标存储桶。 +- 使用 RustFS 凭证和区域 `us-east-1` 配置 AWS CLI。 +- 使用有权执行所需策略管理操作的凭证。 + +设置可复用变量: + +```bash +export RUSTFS_ENDPOINT=http://localhost:9000 +export BUCKET_NAME=my-bucket +``` + +策略管理需要以下操作: + +| 操作 | 所需操作权限 | +| --- | --- | +| 应用或替换策略 | `s3:PutBucketPolicy` | +| 读取策略 | `s3:GetBucketPolicy` | +| 读取公共状态 | `s3:GetBucketPolicyStatus` | +| 删除策略 | `s3:DeleteBucketPolicy` | + +### 策略文档结构 + +存储桶策略使用版本 `2012-10-17` 和 `Statement` 数组: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PublicReadObjects", + "Effect": "Allow", + "Principal": "*", + "Action": ["s3:GetObject"], + "Resource": ["arn:aws:s3:::my-bucket/public/*"] + } + ] +} +``` + +存储桶 ARN 与对象 ARN 不同: + +| 资源 | ARN 格式 | 操作示例 | +| --- | --- | --- | +| 存储桶 | `arn:aws:s3:::my-bucket` | `s3:ListBucket`、`s3:GetBucketLocation` | +| 对象 | `arn:aws:s3:::my-bucket/*` | `s3:GetObject`、`s3:PutObject`、`s3:DeleteObject` | + +在对象 ARN 中使用前缀(如 `arn:aws:s3:::my-bucket/public/*`),可将访问权限限制到存储桶的一部分。完整的语句格式和支持的条件运算符请参阅[用户、组和策略](/security-compliance/iam/policies#policy-document-format)。 + +### 公共访问阻止 + +如果存储桶的公共访问阻止配置启用了 `BlockPublicPolicy`,RustFS 会拒绝包含通配符主体 `Allow` 语句的新策略。除非确实需要匿名访问,否则请保持启用此保护。 + +公共访问阻止不能替代细致的策略审查。现有的显式 `Deny` 仍会覆盖允许,已验证身份的请求也会继续根据 IAM 和存储桶策略进行评估。 + +## 使用 + +### 创建公共读取策略 + +创建仅允许从 `public/` 前缀匿名下载的策略: + +```bash +cat > /tmp/my-bucket-policy.json <<'EOF' +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PublicReadObjects", + "Effect": "Allow", + "Principal": "*", + "Action": ["s3:GetObject"], + "Resource": ["arn:aws:s3:::my-bucket/public/*"] + } + ] +} +EOF +``` + +此策略不允许匿名列出存储桶、上传、覆盖或删除对象。 + +### 应用策略 + +```bash +aws s3api put-bucket-policy \ + --bucket "$BUCKET_NAME" \ + --policy file:///tmp/my-bucket-policy.json \ + --endpoint-url "$RUSTFS_ENDPOINT" +``` + +应用另一个策略会替换完整的现有策略。更新前请获取并检查当前文档;系统不会自动合并语句。 + +### 读取策略 + +```bash +aws s3api get-bucket-policy \ + --bucket "$BUCKET_NAME" \ + --endpoint-url "$RUSTFS_ENDPOINT" \ + --query Policy \ + --output text +``` + +RustFS 会保留提交的策略 JSON。如果策略不存在,API 会返回 `NoSuchBucketPolicy`。 + +### 检查公共状态 + +```bash +aws s3api get-bucket-policy-status \ + --bucket "$BUCKET_NAME" \ + --endpoint-url "$RUSTFS_ENDPOINT" +``` + +响应包含概要公共访问状态: + +```json +{ + "PolicyStatus": { + "IsPublic": false + } +} +``` + +当前状态检查会检测匿名列出存储桶(`s3:ListBucket`)和上传(`s3:PutObject`)。仅公开对象下载的策略(如上面的 `public/` 示例)仍可能报告 `false`。请始终测试准确的匿名操作、对象前缀和条件,不要将此状态视为完整的访问分析。 + +### 删除策略 + +```bash +aws s3api delete-bucket-policy \ + --bucket "$BUCKET_NAME" \ + --endpoint-url "$RUSTFS_ENDPOINT" +``` + +删除存储桶策略只会删除该资源策略。附加到用户和组的 IAM 策略保持不变。 + +## 验证 + +使用已验证身份的凭证上传测试对象: + +```bash +printf 'hello from RustFS\n' > /tmp/hello.txt + +aws s3api put-object \ + --bucket "$BUCKET_NAME" \ + --key public/hello.txt \ + --body /tmp/hello.txt \ + --endpoint-url "$RUSTFS_ENDPOINT" +``` + +确认无需凭证即可下载允许访问的对象: + +```bash +curl --fail-with-body \ + "${RUSTFS_ENDPOINT}/${BUCKET_NAME}/public/hello.txt" +``` + +然后确认允许范围之外的对象不是公开对象: + +```bash +aws s3api put-object \ + --bucket "$BUCKET_NAME" \ + --key private/hello.txt \ + --body /tmp/hello.txt \ + --endpoint-url "$RUSTFS_ENDPOINT" + +curl --fail-with-body \ + "${RUSTFS_ENDPOINT}/${BUCKET_NAME}/private/hello.txt" +``` + +第二个 `curl` 请求应以 `AccessDenied` 失败。还应测试依赖该策略的每种已验证身份用户角色,尤其是文档包含条件或显式拒绝语句时。 + +## 后续步骤 + +- [管理 IAM 策略](/security-compliance/iam/policies) +- [管理凭证](/operations/credentials) +- [配置审计日志](/security-compliance/audit-logs) \ No newline at end of file diff --git a/content/zh/administration/data/bucket/quota.md b/content/zh/administration/data/bucket/quota.md new file mode 100644 index 000000000..89a4518c5 --- /dev/null +++ b/content/zh/administration/data/bucket/quota.md @@ -0,0 +1,204 @@ +--- +title: "存储桶配额" +description: "为单个 RustFS 存储桶配置、检查和验证硬存储配额。" +--- + +RustFS 存储桶配额限制单个存储桶中存储的对象数据总量。使用配额可防止一个工作负载占用超过分配的容量,同时允许其他存储桶使用剩余存储空间。 + +## 概述 + +RustFS 目前支持基于字节的硬配额。接受写入前,RustFS 会将存储桶当前用量加上请求的对象大小,并与配置的限制比较。超过限制的写入会被拒绝,并返回 `InvalidRequest` 和 `Bucket quota exceeded` 消息。 + +配额检查涵盖以下操作: + +| 操作 | 配额行为 | +| --- | --- | +| 上传对象 | 当前用量加对象大小超过限制时拒绝上传。 | +| 完成分段上传 | 提交上传前检查完成后的对象大小。 | +| 将对象复制到存储桶 | 根据目标存储桶配额检查源对象大小。 | +| 删除对象 | 始终允许,以便释放容量。 | + +配额适用于对象数据,而不是对象数量或请求速率。未配置限制的存储桶不受容量限制。 + +:::note[替换上传] + +配额检查会根据存储桶当前用量为传入对象的完整大小预留空间。因此,替换现有键可能需要足以容纳整个替换对象的可用空间。 + +::: + +## 在控制台中配置 + +1. 登录 RustFS 控制台并打开 **Browser**。 +2. 找到存储桶并选择 **Settings**。 +3. 在 **Capacity & Metadata** 下找到 **Bucket Quota**,然后选择 **Edit**。 +4. 启用 **Bucket Quota**。 +5. 输入配额大小并选择 **MiB**、**GiB**、**TiB** 或 **PiB**。 +6. 选择 **Save Quota**。 + +![包含配额大小和单位控件的存储桶配额设置对话框](./images/bucket-quota-console.png) + +如需取消限制,请再次打开对话框,禁用 **Bucket Quota** 并保存更改。 + +## 使用 rc + +为 RustFS 部署配置别名: + +```bash +rc alias set rustfs http://localhost:9000 \ + \ + --region us-east-1 --bucket-lookup path +``` + +当 `rc` 在其他主机上运行时,请将 `localhost` 替换为 RustFS 服务器地址。 + +### 权限 + +配额操作需要以下策略操作权限: + +| 操作 | 所需操作权限 | +| --- | --- | +| 设置或清除配额 | `admin:SetBucketQuota` | +| 读取配额配置或统计信息 | `s3:GetBucketQuota` | +| 检查建议操作是否符合配额 | `s3:GetBucketQuota` | + +根凭证拥有这些权限。进行委派管理时,只附加工作流所需的操作权限。 + +### 设置配额 + +设置 1 GiB 硬配额。`rc` 接受字节值或 `1G`、`500M` 和 `10KB` 等单位: + +```bash +rc bucket quota set rustfs/my-bucket 1G +``` + +响应包含配置的限制和当前用量: + +```text +Bucket: my-bucket +Quota: 1 GiB +Usage: 0 B +Type: HARD +``` + +### 读取配额 + +```bash +rc bucket quota info rustfs/my-bucket +``` + +其他工具需要处理结果时,请使用 `--json`: + +```bash +rc bucket quota info rustfs/my-bucket --json +``` + +未配置限制时,人类可读输出会报告 `Quota: unlimited`。 + +:::note[配置传播] + +设置或清除配额后立即查询,可能会短暂返回之前的状态。开始验证工作流前,请再次查询配额并确认值符合预期。 + +::: + +### 清除配额 + +删除限制但不删除对象: + +```bash +rc bucket quota clear rustfs/my-bucket +rc bucket quota info rustfs/my-bucket +``` + +应用配置更改后,存储桶将不再受容量限制。 + +## 高级配额检查 + +`rc 0.1.29` 不提供详细用量统计或建议写入检查命令。请使用 RustFS Admin API 执行这些操作。请求必须使用 AWS Signature Version 4 和有效的 RustFS 凭证。 + +示例使用以下 shell 变量: + +```bash +export RUSTFS_ENDPOINT=http://localhost:9000 +export RUSTFS_ACCESS_KEY= +export RUSTFS_SECRET_KEY= +export BUCKET_NAME=my-bucket +``` + +:::warning[保护凭证] + +环境变量便于本地测试,但可能对以同一操作系统用户身份运行的进程可见。生产环境请使用平台的密钥管理器或权限受限的凭证文件。 + +::: + +### 读取详细用量统计信息 + +使用统计端点获取限制、当前用量、剩余字节数和已用百分比: + +```bash +curl --fail-with-body \ + --aws-sigv4 "aws:amz:us-east-1:s3" \ + --user "${RUSTFS_ACCESS_KEY}:${RUSTFS_SECRET_KEY}" \ + "${RUSTFS_ENDPOINT}/rustfs/admin/v3/quota-stats/${BUCKET_NAME}" +``` + +```json +{ + "bucket": "my-bucket", + "quota_limit": 1073741824, + "current_usage": 1048576, + "remaining_quota": 1072693248, + "usage_percentage": 0.09765625 +} +``` + +用量值来自 RustFS 数据用量统计。将统计响应用于外部计费或编排前,请留出时间让该视图反映最近的更改。 + +### 检查建议上传 + +在不写入对象的情况下,检查 64 MiB 上传是否符合配额: + +```bash +curl --fail-with-body \ + --aws-sigv4 "aws:amz:us-east-1:s3" \ + --user "${RUSTFS_ACCESS_KEY}:${RUSTFS_SECRET_KEY}" \ + --request POST \ + --header "Content-Type: application/json" \ + --data '{"operation_type":"PUT","operation_size":67108864}' \ + "${RUSTFS_ENDPOINT}/rustfs/admin/v3/quota-check/${BUCKET_NAME}" +``` + +`allowed` 字段报告判定结果。此检查仅供参考:另一个写入可能在计划的上传开始前消耗容量,因此实际上传结果才是最终依据。 + +## 验证 + +设置较小的测试配额,上传一个符合配额的对象,然后尝试上传超过剩余容量的对象: + +```bash +rc bucket quota set rustfs/my-bucket 1M + +dd if=/dev/zero of=/tmp/quota-small.bin bs=1024 count=256 +dd if=/dev/zero of=/tmp/quota-large.bin bs=1048576 count=2 + +rc object copy /tmp/quota-small.bin rustfs/my-bucket/hello.bin +rc object copy /tmp/quota-large.bin rustfs/my-bucket/too-large.bin +``` + +256 KiB 对象可成功上传。2 MiB 对象超过 1 MiB 存储桶配额,因此 `rc` 会报错退出,RustFS 不会创建 `too-large.bin`。 + +删除第一个对象并清除测试配额: + +```bash +rc object remove rustfs/my-bucket/hello.bin --force +rc bucket quota clear rustfs/my-bucket +rc bucket quota info rustfs/my-bucket +``` + +确认最终查询报告 `Quota: unlimited`。 + +如果配额执行无法读取或解析其内部配置,RustFS 会记录 `Bucket quota check degraded to allow` 并允许写入。请监控此警告,因为它表示配额执行暂时不可用。 + +## 后续步骤 + +- [创建存储桶](./creation.md) +- [管理生命周期规则](../lifecycle-management.md) +- [配置可观测性](/operations/observability) \ No newline at end of file diff --git a/content/zh/administration/data/bucket/replication.md b/content/zh/administration/data/bucket/replication.md new file mode 100644 index 000000000..226bf72e0 --- /dev/null +++ b/content/zh/administration/data/bucket/replication.md @@ -0,0 +1,298 @@ +--- +title: "存储桶复制" +description: "配置、验证和监控已启用版本控制的 RustFS 存储桶之间的异步复制。" +--- + +RustFS 存储桶复制会将选定的对象版本从源存储桶复制到目标存储桶。使用它可维护存储桶数据的远程副本、在部署之间分发对象,或为恢复工作流准备辅助副本。 + +## 概述 + +存储桶复制包含两层配置: + +1. **远程目标**存储目标端点、存储桶、凭证和生成的目标 ARN。 +2. S3 **复制配置**将规则附加到源存储桶,并引用该目标 ARN。 + +源存储桶和目标存储桶都必须启用版本控制。注册远程目标时,RustFS 会验证目标连接和目标存储桶的版本控制。如果已启用规则引用未知或过期的目标 ARN,RustFS 会拒绝该复制配置。 + +复制默认以异步方式进行。源端上传成功表示 RustFS 已接受源对象,并不表示目标副本已经完成。 + +规则可以按前缀或对象标签选择对象,并控制以下行为: + +| 规则设置 | 行为 | +| --- | --- | +| `Status` | 启用或禁用规则。 | +| `Filter` | 按键前缀、对象标签或两者限制复制。 | +| `ExistingObjectReplication` | 设置为 `Enabled` 时,包括规则创建前已存在的对象。 | +| `DeleteMarkerReplication` | 设置为 `Enabled` 时,复制删除标记。 | +| `DeleteReplication` | 设置为 `Enabled` 时,复制特定对象版本的删除操作。 | +| `Destination` | 通过 ARN 标识已注册的远程目标。 | + +存储桶复制是单向的。如果两个存储桶都必须接受写入并相互复制,请在相反方向配置单独的目标和规则。不要将存储桶复制与[站点复制](/operations/high-availability/site-replication)混淆,后者会同步更广泛的站点配置和身份数据。 + +## 配置 + +### 要求 + +- 一个源 RustFS 部署和一个可访问的 S3 兼容目标部署。 +- 已启用版本控制的源存储桶和目标存储桶。 +- 专用目标凭证,有权检查目标存储桶的版本控制,并写入复制的对象版本和删除标记。 +- 有权管理远程目标和复制配置的源端管理员。 +- 所有可能执行复制任务的源节点都能通过网络访问目标端点。 +- 管理主机上已安装 RustFS [`rc`](/operations/rc) 客户端。 + +为每个部署配置一个 `rc` 别名。请使用专用凭证,并在运行命令前替换示例端点: + +```bash +rc alias set source https://source.example.com:9000 \ + \ + --region us-east-1 --bucket-lookup path + +rc alias set target https://target.example.com:9000 \ + \ + --region us-east-1 --bucket-lookup path + +rc alias list +``` + +源部署注册远程目标时会使用目标别名凭证。`rc alias list` 会显示端点,但不会输出秘密密钥。 + +:::warning[保护目标凭证] + +RustFS 会将目标凭证作为源存储桶远程目标配置的一部分进行存储。请使用访问范围仅限目标存储桶的专用凭证,不要重复使用根凭证。 + +::: + +### 权限 + +源端管理使用以下策略操作权限: + +| 操作 | 所需操作权限 | +| --- | --- | +| 注册、更新或删除远程目标 | `admin:SetBucketTarget` | +| 列出远程目标 | `admin:GetBucketTarget` | +| 读取复制指标 | `admin:GetReplicationMetrics` | +| 应用或删除复制配置 | `s3:PutReplicationConfiguration` | +| 读取复制配置 | `s3:GetReplicationConfiguration` | + +目标凭证必须通过 RustFS 目标验证,该验证会检查存储桶访问、版本控制、复制对象写入、复制删除标记和对象版本删除。源存储桶启用对象锁定时,目标必须具有兼容的对象锁定支持。 + +### 创建存储桶并启用版本控制 + +创建源存储桶: + +```bash +rc bucket create source/my-bucket +``` + +创建目标存储桶: + +```bash +rc bucket create target/my-bucket-replica +``` + +为两个存储桶启用版本控制: + +```bash +rc bucket version enable source/my-bucket +rc bucket version enable target/my-bucket-replica + +rc bucket version info source/my-bucket +rc bucket version info target/my-bucket-replica +``` + +配置复制期间,不要暂停源存储桶的版本控制。 + +## 使用 + +### 在控制台中配置复制 + +RustFS 控制台将远程目标注册和复制规则配置合并在一个表单中。 + +1. 登录源部署的控制台。 +2. 打开 **Buckets**,找到源存储桶并选择 **Settings**。 +3. 在 **Data Protection** 下,如果 **Versioning** 已禁用,请将其启用。 +4. 在 **Automation** 下,选择 **Open Bucket Replication**。 +5. 选择 **Add Replication Rule**。 +6. 配置目标和规则: + +| 控制台字段 | 值 | +| --- | --- | +| **Priority** | 规则评估优先级。初始值为 `1`。 | +| **Mode** | 选择 **Asynchronous** 或 **Synchronous**。默认选择异步模式。 | +| **Endpoint** | 目标 S3 API 地址,格式为 `host:port`,不含 URL 方案。 | +| **Bucket** | 已启用版本控制的目标存储桶名称。 | +| **Access Key** 和 **Secret Key** | 有权复制到目标存储桶的专用凭证。 | +| **Region** | 目标区域。初始值为 `us-east-1`。 | +| **Storage Class** | 在目标端应用的存储类。初始值为 `STANDARD`。 | +| **Prefix** | 用于限制匹配对象的可选键前缀。 | +| **Tags** | 可选的对象标签名称和值筛选条件。选择 **Add Tag** 可添加更多筛选条件。 | +| **Use TLS** | 为目标连接启用 HTTPS。 | +| **Replicate Existing Objects** | 包括规则创建前的对象。默认启用。 | +| **Replicate Delete Markers** | 将删除标记复制到目标。默认启用。 | +| **Replicate Delete** | 复制特定对象版本的删除操作。默认启用。 | +| **Health Check Interval** | 目标健康检查间隔,以秒为单位。初始值为 `60`。 | +| **Bandwidth Limit** | 每个目标的传输限制,可选择 KiB/s、MiB/s 或 GiB/s。 | + +7. 选择 **Save**。RustFS 会先验证源存储桶、目标连接、目标凭证和目标存储桶的版本控制,再接受该规则。 +8. 返回 **Bucket Replication** 查看规则,或选择 **Refresh** 更新显示的状态。 + +:::warning[在两个部署上启用版本控制] + +保存规则前,源存储桶和目标存储桶都必须启用版本控制。需要时,请登录目标部署的控制台,并在 **Buckets** → **Settings** → **Data Protection** 下启用版本控制。 + +::: + +如需可重复的自动化或配置管理,请使用下面的 `rc` 工作流。 + +### 使用 rc 添加复制规则 + +创建异步规则,复制新对象和现有对象,并传播删除标记和显式版本删除: + +```bash +rc bucket replication add source/my-bucket \ + --remote-bucket target/my-bucket-replica \ + --id replicate-all \ + --priority 1 \ + --replicate delete,delete-marker,existing-objects +``` + +`rc` 会注册目标、获取生成的 ARN,并在一次操作中应用复制规则。不需要某种行为时,请省略相应的 `--replicate` 标志。仅当写入必须等待同步复制时添加 `--sync`。 + +要将复制限制到某个前缀,请添加 `--prefix`: + +```bash +rc bucket replication add source/my-bucket \ + --remote-bucket target/my-bucket-replica \ + --id replicate-documents \ + --priority 2 \ + --prefix documents/ \ + --replicate delete-marker,existing-objects +``` + +不匹配任何已启用规则的对象只会保留在源存储桶中。使用 `--bandwidth` 设置每秒字节数限制,使用 `--healthcheck-seconds` 更改目标健康检查间隔,使用 `--storage-class` 覆盖目标存储类。 + +### 列出和更新规则 + +列出活动规则: + +```bash +rc bucket replication list source/my-bucket +rc bucket replication list source/my-bucket --json +``` + +按 ID 更新规则。只有提供的设置会被更改: + +```bash +rc bucket replication update source/my-bucket \ + --id replicate-all \ + --priority 2 \ + --bandwidth 104857600 \ + --healthcheck-seconds 60 +``` + +使用 `--status Enabled|Disabled` 启用或禁用规则,使用 `--sync true|false` 更改复制模式。 + +### 导出和导入配置 + +导出完整复制配置以供检查或备份: + +```bash +rc bucket replication export source/my-bucket --json > replication.json +``` + +导出内容包括远程目标元数据和目标 Access Key,但不包括 Secret Key。请将该文件作为敏感配置加以保护。 + +导入之前导出的配置: + +```bash +rc bucket replication import source/my-bucket replication.json +``` + +### 删除复制配置 + +```bash +rc bucket replication remove source/my-bucket --id replicate-all + +# Remove every replication rule from the bucket. +rc bucket replication remove source/my-bucket --all +``` + +RustFS 还会删除被已删除配置引用的复制远程目标。它不会删除已复制到目标存储桶的对象或版本。请根据目标存储桶的生命周期和保留要求删除或保留这些对象。 + +:::note[rc 0.1.29 删除响应] + +RustFS 删除复制配置及其目标后,`rc 0.1.29` 在尝试再次清理目标时可能会报告 `Remote target not found`。运行 `rc bucket replication list source/my-bucket --json`;空的 `rules` 数组可确认配置已删除。 + +::: + +## 验证 + +### 检查目标就绪状态 + +创建规则前,`rc bucket replication add` 会检查源端访问、目标连接、目标凭证和存储桶版本控制。确认生成的目标和规则设置: + +```bash +rc bucket replication list source/my-bucket --json +``` + +### 复制对象 + +将测试对象上传到源端: + +```bash +printf 'hello from RustFS replication\n' > /tmp/hello.txt +rc object copy /tmp/hello.txt source/my-bucket/hello.txt +``` + +检查源对象: + +```bash +rc object stat source/my-bucket/hello.txt --json +``` + +复制默认以异步方式进行,因此目标对象可能不会立即出现。重复运行以下命令,直到成功: + +```bash +rc object stat target/my-bucket-replica/hello.txt --json +rc object show target/my-bucket-replica/hello.txt +``` + +比较源对象和目标对象的 `etag` 与 `size_bytes` 值,然后确认 `object show` 返回预期内容。 + +要验证删除标记复制,请删除源对象并列出两个存储桶上的版本: + +```bash +rc object remove source/my-bucket/hello.txt --force + +rc bucket version list source/my-bucket/hello.txt --json +rc bucket version list target/my-bucket-replica/hello.txt --json +``` + +删除标记复制成功后,两个存储桶的最新条目均显示 `is_delete_marker: true`。 + +### 检查复制指标 + +```bash +rc bucket replication status source/my-bucket +rc bucket replication status source/my-bucket --json +``` + +该命令返回源节点当前的内存中复制统计信息。即使对象已到达目标端,指标仍可能为零,因此请将其与目标对象和版本检查结合使用,不要将其作为唯一验证信号。 + +### 排查故障 + +| 现象 | 检查项 | +| --- | --- | +| `bucket versioning must be enabled` | 在源存储桶上启用版本控制。 | +| 目标注册报告 `not versioned` | 在目标存储桶上启用版本控制。 | +| `replication target configuration not found` | 重新检查目标别名、凭证和目标存储桶,然后再次运行 `replication add`。 | +| 规则报告目标已过期 | 刷新规则列表并重试 `replication add`;如果问题仍然存在,请删除失败的配置并重新创建目标。 | +| 目标对象未出现 | 检查目标可访问性、凭证、目标配额和 `rc bucket replication status`。 | +| 复制失败 | 在源节点日志中检查目标 ARN 和对象键。 | +| 不允许删除目标 | 删除或替换复制配置后,再删除被引用的目标。 | + +## 后续步骤 + +- [管理存储桶生命周期](../lifecycle-management.md) +- [配置存储桶配额](./quota.md) +- [配置可观测性](/operations/observability) \ No newline at end of file diff --git a/content/zh/administration/data/lifecycle-management.md b/content/zh/administration/data/lifecycle-management.md new file mode 100644 index 000000000..47a15b4a0 --- /dev/null +++ b/content/zh/administration/data/lifecycle-management.md @@ -0,0 +1,145 @@ +--- +title: "生命周期管理" +description: "使用 rc 命令行客户端配置、检查和维护 RustFS 对象生命周期规则。" +--- + +RustFS 生命周期管理将过期和转换规则应用于存储桶中的对象。本页介绍如何使用 `rc` 管理这些规则、验证转换,以及为已转换的数据恢复临时本地副本。 + +开始前,请[安装 `rc`](/operations/rc),配置名为 `local` 的别名并创建 `my-bucket`。如需转换对象,请先在[分层存储](/administration/data/tiered-storage)中注册目标,并记下其大写层级名称。 + +:::note[异步评估] + +生命周期规则不会立即处理每个符合条件的对象。[对象扫描器](/administration/data/object/scanner)会在后台评估生命周期任务。 + +::: + +## 添加过期规则 + +让 `logs/` 前缀下的对象在创建 30 天后过期: + +```bash +rc bucket lifecycle rule add local/my-bucket \ + --prefix logs/ \ + --expiry-days 30 +``` + +该命令会创建一条已启用的规则,并返回生成的规则 ID。需要编辑或删除这条特定规则时,请记录该 ID。 + +## 添加转换规则 + +在 90 天后将对象数据移至已注册的 `COLDTIER` 层级: + +```bash +rc bucket lifecycle rule add local/my-bucket \ + --transition-days 90 \ + --storage-class COLDTIER +``` + +`--storage-class` 必须与已注册的层级名称匹配。添加规则不会创建层级,也不会将 AWS 存储类标签验证为 RustFS 层级。 + +可以在一条规则中组合过期和转换选项。仅对已启用版本控制的存储桶使用非当前版本选项: + +```bash +rc bucket lifecycle rule add local/my-bucket \ + --noncurrent-transition-days 30 \ + --noncurrent-transition-storage-class COLDTIER \ + --noncurrent-expiry-days 365 +``` + +## 检查和更新规则 + +列出当前规则,并记下要更改规则的 ID: + +```bash +rc bucket lifecycle rule list local/my-bucket +``` + +更改规则的过期时间,或在不删除规则的情况下将其禁用: + +```bash +rc bucket lifecycle rule edit local/my-bucket \ + --id \ + --expiry-days 60 +rc bucket lifecycle rule edit local/my-bucket \ + --id \ + --disable true +``` + +按 ID 删除一条规则。仅当确实要删除存储桶的完整生命周期配置时使用 `--all`: + +```bash +rc bucket lifecycle rule remove local/my-bucket --id +rc bucket lifecycle rule remove local/my-bucket --all +``` + +## 导出和导入规则 + +批量更改前,导出存储桶的生命周期配置: + +```bash +rc bucket lifecycle rule export local/my-bucket > lifecycle.json +``` + +导入文件会替换发送到存储桶的生命周期配置。应用前请检查 JSON: + +```bash +rc bucket lifecycle rule import local/my-bucket lifecycle.json +``` + +## 确认生命周期转换 + +对象满足生命周期规则的条件后,在源集群上检查该对象: + +```bash +aws s3api head-object \ + --bucket my-bucket \ + --key hello.txt \ + --endpoint-url http://localhost:9000 +``` + +转换完成后,响应会将已注册的层级名称报告为存储类: + +```json +{ + "StorageClass": "COLDTIER" +} +``` + +响应可能包含其他对象元数据。转换完成前,`StorageClass` 可能不存在,也可能尚未报告为 `COLDTIER`。 + +照常通过源 RustFS 端点读取对象: + +```bash +aws s3 cp \ + s3://my-bucket/hello.txt \ + /path/to/hello.txt \ + --endpoint-url http://localhost:9000 +``` + +RustFS 通过源存储桶和对象键读取已转换的数据。应用无需直接访问目标存储桶。 + +## 恢复本地副本 + +请求已转换对象的临时本地副本,并保留七天: + +```bash +rc bucket lifecycle restore local/my-bucket/hello.txt --days 7 +``` + +回迁副本期间,`HEAD` 会报告 `x-amz-restore: ongoing-request="true"`。完成后,它会报告 `ongoing-request="false"` 和到期日期。在恢复进行期间再次提交恢复请求会返回 `RestoreAlreadyInProgress`。 + +恢复期限到期后,RustFS 会删除本地恢复副本及其恢复元数据。已转换的对象仍可从远程层级访问。 + +## 命令兼容性 + +最新版本的 `rc` 也接受 `rc ilm` 作为兼容别名。对于新命令和脚本,我们建议使用名词优先的 `rc bucket lifecycle` 形式: + +```bash +rc bucket lifecycle --help +rc bucket lifecycle rule --help +rc bucket lifecycle tier --help +``` + +## 后续步骤 + +查看[分层存储](/administration/data/tiered-storage)以监控或维护远程层级,并使用[创建对象](/administration/data/object/creation)为生命周期规则创建测试对象。 \ No newline at end of file diff --git a/content/zh/administration/data/meta.json b/content/zh/administration/data/meta.json new file mode 100644 index 000000000..43019cad8 --- /dev/null +++ b/content/zh/administration/data/meta.json @@ -0,0 +1,9 @@ +{ + "title": "数据管理", + "pages": [ + "object", + "bucket", + "tiered-storage", + "lifecycle-management" + ] +} \ No newline at end of file diff --git a/content/zh/administration/data/object/creation.md b/content/zh/administration/data/object/creation.md new file mode 100644 index 000000000..076f91629 --- /dev/null +++ b/content/zh/administration/data/object/creation.md @@ -0,0 +1,81 @@ +--- +title: "创建对象" +description: "使用 RustFS UI、rc 或 S3 API 创建对象。" +--- + +对象是 RustFS 中的基本存储单元,包含数据、元数据和唯一键。本指南介绍如何创建(上传)对象。 + +## 要求 + +- 正在运行的 RustFS 实例(参阅[安装指南](../../../installation/index.md))。 +- 已安装 [`rc`](/operations/rc),并为命令行工作流配置了别名。 +- 目标存储桶。按照[创建存储桶](../bucket/creation.md)中的步骤创建一个存储桶。 + +## 创建对象 + +### 使用 RustFS UI + +1. 登录 RustFS 控制台。 +2. 选择目标存储桶。 +3. 在存储桶页面右上角,选择 **New Directory**、**New File** 或 **Upload File/Folder**。 +4. 如需从本地计算机上传,请单击 **Upload File/Folder**,选择文件,然后单击 **Start Upload**。 + +![通过 UI 创建对象](images/upload_file_from_ui.png) + +单击对象可查看其详细信息。 + +![对象详细信息](images/object_details_info.png) + +### 使用 `rc` + +有关安装和别名配置,请参阅 [`rc` 指南](/operations/rc)。 + +上传文件: + +```bash +rc object copy /path/to/hello.txt rustfs/my-bucket/hello.txt +rc object list rustfs/my-bucket +``` + +在 RustFS 控制台中确认上传结果。 + +### 使用 API + +通过 API 上传文件: + +```http +PUT /{bucketName}/{objectName} HTTP/1.1 +``` + +S3 请求必须使用 AWS Signature V4 签名,因此请使用 S3 客户端,不要手动构造请求头。为访问密钥配置 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 后,运行: + +```bash +aws s3api put-object \ + --bucket bucket-creation-by-api \ + --key hello.txt \ + --body /path/to/hello.txt \ + --endpoint-url http://localhost:9000 +``` + +在 RustFS 控制台中确认上传结果。 + +## 删除对象 + +请参阅[删除对象](./deletion.md)。 + +使用以下 API 删除文件: + +```http +DELETE /{bucketName}/{objectName} HTTP/1.1 +``` + +请求示例: + +```bash +aws s3api delete-object \ + --bucket bucket-creation-by-api \ + --key hello.txt \ + --endpoint-url http://localhost:9000 +``` + +可以在 RustFS UI 中确认文件已删除。 \ No newline at end of file diff --git a/content/zh/administration/data/object/deletion.md b/content/zh/administration/data/object/deletion.md new file mode 100644 index 000000000..e003f5e82 --- /dev/null +++ b/content/zh/administration/data/object/deletion.md @@ -0,0 +1,55 @@ +--- +title: "删除对象" +description: "使用 RustFS UI、rc 或 S3 API 删除对象。" +--- + +本指南介绍如何删除对象。 + +## 要求 + +- 使用命令行工作流前,请安装并配置 [`rc`](/operations/rc)。 +- 删除对象前,请确认别名、存储桶和对象键。 + +## 使用 RustFS UI + +1. 登录 RustFS 控制台。 +2. 选择包含待删除文件的存储桶。 +3. 在存储桶页面选择待删除文件。 +4. 单击右上角的 **Delete Selected Items**,然后在弹出对话框中单击 **Confirm**。 + +![通过 UI 删除对象](images/delete_file_from_ui.png) + +## 使用 `rc` + +删除文件: + +```bash +rc object remove rustfs/my-bucket/hello.txt +rc object list rustfs/my-bucket +``` + +```text +Removed: rustfs/my-bucket/hello.txt +✓ Removed 1 object(s). +``` + +在 RustFS 控制台中确认删除结果。 + +## 使用 API + +通过 API 删除文件: + +```http +DELETE /{bucketName}/{objectName} HTTP/1.1 +``` + +S3 请求必须使用 AWS Signature V4 签名,因此请使用 S3 客户端,不要手动构造请求头。为访问密钥配置 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 后,运行: + +```bash +aws s3api delete-object \ + --bucket bucket-creation-by-api \ + --key hello.txt \ + --endpoint-url http://localhost:9000 +``` + +在 RustFS 控制台中确认删除结果。 \ No newline at end of file diff --git a/content/zh/administration/data/object/images/delete_file_from_ui.png b/content/zh/administration/data/object/images/delete_file_from_ui.png new file mode 100644 index 000000000..171c3e3b4 Binary files /dev/null and b/content/zh/administration/data/object/images/delete_file_from_ui.png differ diff --git a/content/zh/administration/data/object/images/multipart-upload-console.png b/content/zh/administration/data/object/images/multipart-upload-console.png new file mode 100644 index 000000000..5276735ce Binary files /dev/null and b/content/zh/administration/data/object/images/multipart-upload-console.png differ diff --git a/content/zh/administration/data/object/images/object-lock-create-bucket.png b/content/zh/administration/data/object/images/object-lock-create-bucket.png new file mode 100644 index 000000000..6264eb175 Binary files /dev/null and b/content/zh/administration/data/object/images/object-lock-create-bucket.png differ diff --git a/content/zh/administration/data/object/images/object_details_info.png b/content/zh/administration/data/object/images/object_details_info.png new file mode 100644 index 000000000..086f2eabf Binary files /dev/null and b/content/zh/administration/data/object/images/object_details_info.png differ diff --git a/content/zh/administration/data/object/images/upload_file_from_ui.png b/content/zh/administration/data/object/images/upload_file_from_ui.png new file mode 100644 index 000000000..c09abff33 Binary files /dev/null and b/content/zh/administration/data/object/images/upload_file_from_ui.png differ diff --git a/content/zh/administration/data/object/meta.json b/content/zh/administration/data/object/meta.json new file mode 100644 index 000000000..e83eec7c7 --- /dev/null +++ b/content/zh/administration/data/object/meta.json @@ -0,0 +1,11 @@ +{ + "title": "对象", + "pages": [ + "creation", + "deletion", + "object-lock", + "versioning", + "multipart-upload", + "scanner" + ] +} \ No newline at end of file diff --git a/content/zh/administration/data/object/multipart-upload.md b/content/zh/administration/data/object/multipart-upload.md new file mode 100644 index 000000000..df383dfe9 --- /dev/null +++ b/content/zh/administration/data/object/multipart-upload.md @@ -0,0 +1,101 @@ +--- +title: "分段上传" +description: "分段上传大型对象、监控控制台上传任务,并使用 rc 验证已完成的对象。" +--- + +分段上传将一个对象拆分为独立上传的分段,并在服务器上进行组装。它适用于大型对象、可重试传输,以及需要进度和取消控制的浏览器上传。 + +## 概述 + +S3 分段上传工作流包含三个必要阶段: + +1. **CreateMultipartUpload** 返回上传 ID。 +2. **UploadPart** 上传带编号的分段,并为每个分段返回 ETag。 +3. **CompleteMultipartUpload** 提交按顺序排列的分段编号和 ETag,以创建最终对象。 + +使用 **AbortMultipartUpload** 中止未完成的上传,避免临时分段继续占用存储空间。 + +RustFS 接受从 `1` 到 `10000` 的分段编号。`ListParts` 和 `ListMultipartUploads` 每次响应最多返回 1,000 个条目,并使用标记分页。只有完成请求成功后,完整对象才会出现。 + +## 在控制台中上传 + +1. 登录 RustFS 控制台并打开目标存储桶。 +2. 选择 **Upload File/Folder**。 +3. 可选择输入 **Current Prefix**。 +4. 选择 **Select File** 或 **Select Folder**,然后选择要上传的内容。 +5. 检查所选名称和大小,然后选择 **Start Upload**。 + +![已选择大型文件的控制台上传对话框](./images/multipart-upload-console.png) + +观察到的控制台上传对话框支持最多选择 10,000 个文件,并报告单个文件最大为 512 GB。这些是控制台上传限制;S3 客户端可能有不同的本地限制。 + +上传开始后,**Task Management** 会将任务分组为 Pending、Processing、Completed、Failed 和 Canceled 状态。每个处理中的任务都会显示进度和 **Cancel** 操作。取消活动的分段任务会中止当前分段请求,并将任务标记为已取消。 + +完成后刷新存储桶,确认对象大小和修改时间。 + +## 使用 rc + +使用 `rc` 上传并验证对象: + +```bash +rc object copy /path/to/hello.txt rustfs/my-bucket/hello.txt +rc object stat rustfs/my-bucket/hello.txt --json +``` + +:::note[rc 0.1.29 分段上传限制] + +`rc 0.1.29` 不提供创建、上传分段、完成、列出分段或中止分段上传的命令。经过验证,20 MiB 的 `rc object copy` 使用单个 `PutObject` 请求,而不是分段上传。需要显式分段上传行为时,请使用控制台或 S3 SDK;使用 `rc object stat` 验证已完成的对象。 + +::: + +对于启用版本控制的存储桶,列出已完成分段上传所创建的版本: + +```bash +rc bucket version list rustfs/my-bucket/hello.txt --json +``` + +在启用版本控制的存储桶中成功完成分段上传后,RustFS 会返回版本 ID。 + +## S3 分段上传操作 + +使用支持以下标准操作的 S3 SDK: + +| 阶段 | S3 操作 | 必需值 | +| --- | --- | --- | +| 发起 | `CreateMultipartUpload` | 存储桶、键、元数据、加密和可选的对象锁定设置。 | +| 上传 | `UploadPart` | 存储桶、键、上传 ID、分段编号和正文。保存返回的 ETag。 | +| 检查 | `ListParts` | 存储桶、键和上传 ID。需要时进行分页。 | +| 完成 | `CompleteMultipartUpload` | 按顺序排列的分段编号及其准确 ETag。 | +| 取消 | `AbortMultipartUpload` | 存储桶、键和上传 ID。 | +| 查找 | `ListMultipartUploads` | 存储桶和可选前缀。需要时进行分页。 | + +不要将上传 ID 用于其他键。按分段编号升序提交已完成的分段,并完全保留每个 ETag 的返回值。 + +## 验证 + +完成后: + +```bash +rc object stat rustfs/my-bucket/hello.txt --json +rc object show rustfs/my-bucket/hello.txt > /tmp/hello-downloaded.txt +cmp /path/to/hello.txt /tmp/hello-downloaded.txt +``` + +确认 `size_bytes` 与本地文件一致,且 `cmp` 成功退出。对于启用版本控制的存储桶,还要确认 `rc bucket version list` 返回版本 ID。 + +## 故障排除 + +| 现象 | 检查项 | +| --- | --- | +| 上传一直处于 Processing | 检查浏览器连接并保持控制台标签页打开;连接中断时取消并重试。 | +| 分段请求失败 | 使用同一上传 ID 和分段编号重试该分段,然后使用最新返回的 ETag。 | +| 完成操作报告分段无效 | 根据 `ListParts` 验证提交的分段编号、顺序和 ETag。 | +| 上传分段后对象不存在 | 发送 `CompleteMultipartUpload`;仅上传分段不会创建对象。 | +| 临时存储持续增长 | 列出未完成的上传并中止不再需要的上传。 | +| 对锁定键执行完成操作失败 | 检查当前目标版本的对象锁定保留期或依法保留。 | + +## 后续步骤 + +- [创建和检查对象](./creation.md) +- [管理对象版本](./versioning.md) +- [使用对象锁定保护对象](./object-lock.md) \ No newline at end of file diff --git a/content/zh/administration/data/object/object-lock.md b/content/zh/administration/data/object/object-lock.md new file mode 100644 index 000000000..216c5846d --- /dev/null +++ b/content/zh/administration/data/object/object-lock.md @@ -0,0 +1,103 @@ +--- +title: "对象锁定" +description: "使用保留期和依法保留来保护已启用版本控制的对象免遭删除。" +--- + +RustFS 对象锁定为单个对象版本提供一次写入、多次读取保护。使用保留期提供有期限的保护,使用依法保留提供没有预定义到期日期的保护。 + +## 概述 + +对象锁定要求启用存储桶版本控制,并且必须在创建存储桶时启用。每次覆盖都会创建新版本;保留期和依法保留保护的是特定版本,而不是整个对象键。 + +| 保护方式 | 行为 | +| --- | --- | +| `GOVERNANCE` 保留 | 阻止删除和缩短保留期,除非调用者具有绕过权限并显式请求绕过。无需绕过即可延长保留期。 | +| `COMPLIANCE` 保留 | 即使具有治理绕过权限也会阻止删除。日期可以延长,但不能缩短。 | +| 依法保留 | 阻止删除,直到保留状态设置为 `OFF`。它没有到期日期,治理绕过也无法将其覆盖。 | + +删除不带版本 ID 的键会创建删除标记。受保护的版本仍会保留,并可按版本 ID 获取。 + +:::danger[启用前规划保留策略] + +在保留截止日期之前,无法绕过或缩短 COMPLIANCE 保留期。保护生产数据前,请在非生产存储桶中测试策略,并验证时间同步、权限、生命周期规则、复制和备份流程。 + +::: + +## 在控制台中配置 + +1. 登录 RustFS 控制台并打开 **Buckets**。 +2. 选择 **Create Bucket** 并输入存储桶名称。 +3. 启用 **Object Lock**。控制台还会启用 **Version**,因为对象锁定要求版本控制。 +4. 如需自动对新对象版本应用保留期,请启用 **Retention**。 +5. 选择 **COMPLIANCE** 或 **GOVERNANCE**,输入有效期,然后选择 **Day** 或 **Year**。 +6. 选择 **Create**。 + +![启用了版本控制、对象锁定和默认保留期的创建存储桶对话框](./images/object-lock-create-bucket.png) + +启用默认保留期时,控制台最初显示 `180` 天。请将其替换为保留策略要求的期限;这是 UI 初始值,不是通用建议。 + +要检查受保护对象,请打开存储桶,选择对象名称,然后使用 **Versions** 和 **Info** 标签页。Info 标签页会显示 **Legal Hold** 和 **RetentionPolicy** 字段。 + +## 使用 rc + +运行这些示例前先配置别名: + +```bash +rc alias set rustfs http://localhost:9000 \ + \ + --region us-east-1 --bucket-lookup path +``` + +:::note[rc 0.1.29 存储桶创建限制] + +`rc bucket create --with-lock` 和 `--with-versioning` 会出现在 `rc 0.1.29` 帮助输出中,但执行时会返回 `not implemented`。请在控制台中创建对象锁定存储桶。下面显示的上传请求头受支持,并已针对 RustFS 验证。 + +::: + +上传带 GOVERNANCE 保留期的对象版本。请同时提供两个保留请求头,并使用未来的 RFC 3339 UTC 时间戳: + +```bash +rc object copy /path/to/hello.txt rustfs/my-bucket/hello.txt \ + -H "x-amz-object-lock-mode:GOVERNANCE" \ + -H "x-amz-object-lock-retain-until-date:2027-01-01T00:00:00Z" +``` + +上传启用了依法保留的对象版本: + +```bash +rc object copy /path/to/hello.txt rustfs/my-bucket/legal-hold.txt \ + -H "x-amz-object-lock-legal-hold:ON" +``` + +列出受保护版本并检查特定版本: + +```bash +rc bucket version list rustfs/my-bucket --json +rc object stat rustfs/my-bucket/hello.txt \ + --version-id --json +``` + +`rc 0.1.29` 不提供更改保留期或在 `ON` 与 `OFF` 之间切换现有依法保留状态的命令。请使用控制台或 S3 SDK 执行这些操作。 + +## 验证保护 + +1. 上传带 GOVERNANCE 保留期或依法保留的测试对象。 +2. 使用 `rc bucket version list` 记录其版本 ID。 +3. 通过 S3 客户端尝试在不绕过保护的情况下删除该确切版本。保护生效期间,RustFS 必须返回 `AccessDenied`。 +4. 确认该版本在控制台中仍然可见,并可通过 `rc object stat --version-id` 检查。 + +测试 GOVERNANCE 保留期的绕过功能时,仅使用具有 `s3:BypassGovernanceRetention` 权限的专用管理身份。COMPLIANCE 保留期和依法保留不受治理绕过影响。 + +## 运维注意事项 + +- 默认存储桶保留期在发起新对象版本或分段上传时计算。 +- 复制对象会创建新的目标版本;目标保留策略独立应用。 +- 不应暂停对象锁定存储桶的版本控制。 +- 保留期或依法保留阻止删除时,生命周期过期规则无法删除该版本。 +- 锁定对象的复制目标必须支持兼容的对象锁定行为。 + +## 后续步骤 + +- [管理对象版本](./versioning.md) +- [配置存储桶复制](../bucket/replication.md) +- [查看安全检查清单](/installation/requirement/checklists/security-checklists) \ No newline at end of file diff --git a/content/zh/administration/data/object/scanner.md b/content/zh/administration/data/object/scanner.md new file mode 100644 index 000000000..52149c687 --- /dev/null +++ b/content/zh/administration/data/object/scanner.md @@ -0,0 +1,32 @@ +--- +title: "对象扫描" +description: "介绍 RustFS 对象扫描器的设计、实现和监控。" +--- + +本指南介绍 RustFS 对象扫描器的设计和实现,包括与纠删码、擦洗与修复机制的集成、调度策略、监控指标和故障排除。 + +## 概述 + +RustFS 对象扫描器内置于存储引擎,负责定期检查对象完整性并执行计划操作。 +扫描任务包括磁盘用量统计、生命周期管理规则评估、对象复制执行,以及触发损坏对象的自修复。 + +## 架构和设计原则 + +### 扫描器架构 + +RustFS 扫描器采用哈希采样机制,根据对象名称哈希,每 1024 个对象选择一个进行检查,以尽量降低性能影响。 +扫描器与纠删码模块深度集成,在检测到分片丢失或损坏时利用冗余分片在线重建,确保较高的数据可用性和一致性。 + +## 数据验证和恢复 + +RustFS 数据验证机制会检查元数据一致性,并逐位读取和验证以发现隐藏的坏块。对象扫描器会检测位腐烂等问题,并在必要时触发修复流程。 + +## 扫描模式和调度 + +RustFS 支持三种扫描模式:读取时在线扫描、后台定期扫描和手动全量扫描,以平衡性能与可靠性。 +与 Ceph 中的 `osd_scrub_begin_hour` 配置类似,管理员可以设置扫描开始时间和频率。例如,默认每天进行一次轻量验证。 + +## 监控和指标 + +扫描器统计信息包括任务总数、失败数和耗时分布,并通过 Prometheus 数据模型公开 `rustfs_scanner_jobs_total`、`rustfs_scanner_failures_total` 和 `rustfs_scanner_duration_seconds` 等指标。 +结合监控系统,可以根据扫描失败率和持续时间设置告警,及时发现并定位存储或网络层面的潜在问题。 \ No newline at end of file diff --git a/content/zh/administration/data/object/versioning.md b/content/zh/administration/data/object/versioning.md new file mode 100644 index 000000000..6ef91596e --- /dev/null +++ b/content/zh/administration/data/object/versioning.md @@ -0,0 +1,125 @@ +--- +title: "版本控制" +description: "使用 rc 和控制台启用存储桶版本控制、恢复早期对象版本并管理删除标记。" +--- + +RustFS 存储桶版本控制会保留同一对象键的多个版本。使用它可从意外覆盖和删除中恢复,也是对象锁定和存储桶复制的先决条件。 + +## 概述 + +启用版本控制后: + +- 每次向现有键上传或复制内容都会创建新的版本 ID。 +- 常规删除会创建删除标记,而不会删除旧版本。 +- 不带版本 ID 读取对象键时,会返回最新的可见版本;如果最新条目是删除标记,则返回 `NotFound`。 +- 读取或删除特定版本需要其版本 ID。 + +暂停版本控制会停止常规创建新版本 ID,但会保留现有版本和删除标记。暂停并不等同于禁用版本控制或删除版本历史记录。 + +## 在控制台中配置 + +### 创建存储桶时启用 + +1. 打开 **Buckets** 并选择 **Create Bucket**。 +2. 输入存储桶名称。 +3. 启用 **Version**。 +4. 选择 **Create**。 + +### 为现有存储桶启用或暂停版本控制 + +1. 打开 **Buckets**,找到存储桶并选择 **Settings**。 +2. 在 **Data Protection** 下找到 **Versioning**。 +3. 根据需要启用或暂停版本控制。 + +设置页面会显示 `Enabled`、`Suspended` 或 `Disabled`,并注明暂停会保留现有版本。 + +### 浏览和恢复版本 + +1. 打开存储桶;需要查看被删除标记隐藏的键时,启用 **Show Deleted Objects**。 +2. 选择对象名称以打开 **Object Details**。 +3. 选择 **Versions**,检查可用版本和删除标记。 +4. 下载所需版本并重新上传,使其内容成为最新版本。 + +## 使用 rc + +创建存储桶并启用版本控制: + +```bash +rc bucket create rustfs/my-bucket +rc bucket version enable rustfs/my-bucket +rc bucket version info rustfs/my-bucket +``` + +上传同一键的两个版本: + +```bash +printf 'version one\n' > /tmp/hello.txt +rc object copy /tmp/hello.txt rustfs/my-bucket/hello.txt + +printf 'version two\n' > /tmp/hello.txt +rc object copy /tmp/hello.txt rustfs/my-bucket/hello.txt --overwrite +``` + +列出版本,并记录要恢复版本的 ID: + +```bash +rc bucket version list rustfs/my-bucket/hello.txt --json +rc object stat rustfs/my-bucket/hello.txt \ + --version-id --json +``` + +下载早期版本的内容并将其作为新的最新版本上传,以恢复该版本: + +```bash +rc object show rustfs/my-bucket/hello.txt \ + --version-id > /tmp/hello-restored.txt + +rc object copy /tmp/hello-restored.txt \ + rustfs/my-bucket/hello.txt --overwrite +``` + +删除当前键以创建删除标记,然后检查该标记: + +```bash +rc object remove rustfs/my-bucket/hello.txt --force +rc bucket version list rustfs/my-bucket/hello.txt --json +``` + +最新条目应显示 `is_delete_marker: true`。早期版本仍可通过版本 ID 访问。 + +当不再希望常规写入创建带编号的新版本时,暂停版本控制: + +```bash +rc bucket version suspend rustfs/my-bucket +rc bucket version info rustfs/my-bucket +``` + +:::warning[rc 0.1.29 版本删除限制] + +`rc object remove --versions` 会出现在 `rc 0.1.29` 帮助输出中,但会返回 `not implemented`。请使用控制台或 S3 SDK 永久删除选定的版本 ID。除非已验证保留、复制和恢复要求,否则不要删除完整的版本历史记录。 + +::: + +## 验证 + +启用版本控制后: + +1. 使用不同内容向同一键上传两次。 +2. 运行 `rc bucket version list`,确认两个条目具有不同的版本 ID。 +3. 使用 `rc object show --version-id` 获取每个版本并比较其内容。 +4. 删除不带版本 ID 的键,并确认出现删除标记。 +5. 按版本 ID 获取旧版本,确认该版本仍可恢复。 + +## 运维注意事项 + +- 覆盖和删除会保留旧数据,因此版本控制会增加存储用量。 +- 只有在定义恢复期和保留期后,才为非当前版本配置生命周期规则。 +- 存储桶复制要求源存储桶和目标存储桶均启用版本控制。 +- 对象锁定依赖版本控制,并保护单个版本。 +- 在启用版本控制的存储桶中,完成分段上传会创建一个新对象版本。 + +## 后续步骤 + +- [使用对象锁定保护版本](./object-lock.md) +- [上传大型对象](./multipart-upload.md) +- [管理存储桶生命周期](../lifecycle-management.md) \ No newline at end of file diff --git a/content/zh/administration/data/tiered-storage.md b/content/zh/administration/data/tiered-storage.md new file mode 100644 index 000000000..6cf32ad42 --- /dev/null +++ b/content/zh/administration/data/tiered-storage.md @@ -0,0 +1,179 @@ +--- +title: "分层存储" +description: "配置由生命周期驱动的对象转换,将对象从 RustFS 转移到远程存储层。" +--- + +RustFS 分层存储会将对象从本地存储移至已配置的远程后端。本页说明支持的目标,并介绍如何在控制台中添加和维护 RustFS 存储层。 + +分层是异步的。RustFS 在本地保留对象元数据,将对象数据传输到远程层,并继续通过原始存储桶和对象键提供 S3 读取服务。 + +```mermaid +flowchart LR + A[Application] -->|S3 requests| H[Hot RustFS cluster] + H -->|Lifecycle transition| T[Remote tier bucket] + H -->|Read transitioned object| T +``` + +:::note[层级名称不是 AWS 存储类] + +生命周期规则通过注册时使用的大写名称引用层级,例如 `COLDTIER`。除非已使用完全相同的有效名称注册 RustFS 层级并验证目标行为,否则不要替换为 `INTELLIGENT_TIERING`、`GLACIER` 或 `DEEP_ARCHIVE` 等 AWS 类标签。 + +::: + +## 支持的后端 + +RustFS 源代码为以下目标类型定义了温存储后端实现: + +| 类型 | 配置键 | 常见目标 | +| --- | --- | --- | +| RustFS | `rustfs` | 另一个 RustFS 部署 | +| S3 | `s3` | Amazon S3 或此后端支持的 S3 端点 | +| Wasabi | `wasabi` | Wasabi 对象存储 | +| MinIO | `minio` | MinIO 部署 | +| Aliyun | `aliyun` | 阿里云对象存储服务(OSS) | +| Tencent | `tencent` | 腾讯云对象存储(COS) | +| Huaweicloud | `huaweicloud` | 华为云对象存储服务(OBS) | +| Azure | `azure` | Azure Blob Storage | +| GCS | `gcs` | Google Cloud Storage | +| R2 | `r2` | Cloudflare R2 | + +不同提供商的负载和凭证要求不同。下面的完整工作流使用 RustFS 后端,因为 RustFS 源代码包含此路径从热集群到冷集群的端到端测试。 + +## 开始前 + +请准备以下资源: + +- 用于存储热数据的源 RustFS 部署。 +- 独立的目标 RustFS 部署和已存在的目标存储桶。本示例在目标端使用 `my-bucket`。 +- 有权在该存储桶中放置、获取、列出和删除对象的目标凭证。 +- 源部署的 RustFS 控制台访问权限。 + +生产环境中的两个部署都应使用 TLS。将目标凭证限制到专用的分层存储桶和前缀。 + +## 1. 打开分层存储 + +登录源部署的 RustFS 控制台。在左侧导航中选择 **Tiered Storage**,然后选择右上角的 **Add Tier**。 + +## 2. 选择目标 + +选择目标提供商。本示例使用 **RustFS**,将源部署连接到另一个 RustFS 部署。 + +## 3. 输入目标详细信息 + +填写表单: + +| 字段 | 值 | +| --- | --- | +| **Name (A-Z,0-9,_)** | 输入唯一的大写层级名称,例如 `COLDTIER`。 | +| **Endpoint** | 输入目标 RustFS S3 端点。 | +| **Access Key** | 输入目标部署的访问密钥。 | +| **Secret Key** | 输入目标部署的秘密密钥。 | +| **Bucket** | 输入已存在的目标存储桶名称,例如 `my-bucket`。 | +| **Prefix (Optional)** | 可选择输入分层对象专用的前缀。 | +| **Region** | 可选择输入目标区域,例如 `us-east-1`。 | + +除非目标后端需要其他受支持的存储类,否则保留 **Storage Class** 的默认值。 + +:::warning[保护层级凭证] + +表单包含秘密密钥。请使用仅限目标存储桶和前缀的凭证。不要在截图、工单或日志中暴露密钥。 + +::: + +## 4. 保存层级 + +选择 **Save**。RustFS 会验证后端,并通过写入、读取和删除一个小对象进行探测。如果端点、凭证、存储桶权限或后端配置无法完成探测,保存将失败。 + +层级出现在 **Tiers** 列表后,请在[生命周期管理](/administration/data/lifecycle-management)中配置转换规则。只有生命周期规则引用已注册层级的名称后,层级才会移动对象。 + +## 使用 `rc` 管理层级 + +安装并配置 [`rc`](/operations/rc),然后列出源部署上注册的层级: + +```bash +rc bucket lifecycle tier list local +``` + +使用控制台工作流中所述的相同设置添加 RustFS 层级: + +```bash +rc bucket lifecycle tier add rustfs COLDTIER local \ + --endpoint \ + --access-key \ + --secret-key \ + --bucket my-bucket \ + --region us-east-1 +``` + +检查层级配置和可用统计信息: + +```bash +rc bucket lifecycle tier info COLDTIER local +``` + +其余层级命令用于更新凭证或删除层级: + +```bash +rc bucket lifecycle tier edit COLDTIER local \ + --access-key \ + --secret-key +rc bucket lifecycle tier remove COLDTIER local +``` + +有关创建转换规则、确认转换和恢复本地副本,请参阅[生命周期管理](/administration/data/lifecycle-management)。更改层级前,运行 `rc bucket lifecycle tier --help` 查看提供商特定选项。 + +## 监控层级活动 + +使用带 SigV4 签名且具有 `admin:ListTier` 权限的请求访问层级统计端点: + +```http +GET /rustfs/admin/v3/tier-stats?tier=COLDTIER HTTP/1.1 +Host: +``` + +监控转换失败,同时关注源集群容量和目标端可用性。对于没有已恢复本地副本的对象,配置层级会将目标服务和网络路径加入读取路径。 + +## 更改或删除层级 + +Admin API 提供以下变更路由,均需要 `admin:SetTier`: + +| 操作 | 路由 | +| --- | --- | +| 编辑层级 | `POST /rustfs/admin/v3/tier/{tiername}` | +| 删除层级 | `DELETE /rustfs/admin/v3/tier/{tiername}` | +| 清除所有层级 | `POST /rustfs/admin/v3/tier/clear` | + +编辑或删除层级前: + +1. 禁用引用该层级的生命周期规则。 +2. 确认没有转换任务仍在使用该层级。 +3. 确认没有源对象依赖其目标存储桶或前缀中存储的数据。 +4. 备份层级配置并记录目标位置。 + +常规层级变更会检查后端使用情况并保护非空目标。除非已独立证明每个已转换对象均可恢复,否则不要使用 `force` 选项绕过这些检查。删除活动层级的配置可能导致无法从源集群读取已转换对象。 + +:::warning[不要直接修改层级对象] + +不要重命名、覆盖或删除目标存储桶中生成的对象。请通过热 RustFS 集群管理源对象,以便 RustFS 保持本地转换元数据与远程数据一致。 + +::: + +## Admin API 参考 + +当前 RustFS 源代码注册了以下层级路由: + +| 方法 | 路由 | 权限 | +| --- | --- | --- | +| `PUT` | `/rustfs/admin/v3/tier` | `admin:SetTier` | +| `POST` | `/rustfs/admin/v3/tier/{tiername}` | `admin:SetTier` | +| `DELETE` | `/rustfs/admin/v3/tier/{tiername}` | `admin:SetTier` | +| `POST` | `/rustfs/admin/v3/tier/clear` | `admin:SetTier` | +| `GET` | `/rustfs/admin/v3/tier`(列出配置) | `admin:ListTier` | +| `GET` | `/rustfs/admin/v3/tier/{tier}`(验证连接) | `admin:ListTier` | +| `GET` | `/rustfs/admin/v3/tier-stats`(读取统计信息) | `admin:ListTier` | + +所有 Admin API 请求都需要 SigV4 身份验证。这些路由是管理接口,不是普通 S3 存储桶操作。 + +## 后续步骤 + +查看[生命周期管理](/administration/data/lifecycle-management),并为分层存储所用的管理员和服务凭证配置[访问策略](/security-compliance/iam/policies)。 \ No newline at end of file diff --git a/content/zh/administration/index.md b/content/zh/administration/index.md new file mode 100644 index 000000000..63faab2e9 --- /dev/null +++ b/content/zh/administration/index.md @@ -0,0 +1,16 @@ +--- +title: "管理" +description: "管理 RustFS 数据、访问协议和基于浏览器的管理功能。" +--- + +使用本节可通过控制台管理 RustFS、管理存储桶和对象,以及配置访问协议。 + +## 管理领域 + +- [控制台](./console/index.md)介绍基于浏览器的管理和登录方式。 +- [数据管理](./data/object/object-lock.md)介绍存储桶、对象、生命周期行为和数据保护功能。 +- [协议支持](./protocols/s3.md)介绍 S3、WebDAV、FTPS 和 SFTP 访问。 +- [CORS 配置](./cors/index.md)介绍 RustFS 服务的跨源访问。 +- [虚拟主机访问](/integration/virtual)介绍基于域名的 S3 寻址。 + +有关身份、加密、传输安全和审计,请继续阅读[安全与合规](/security-compliance)。 \ No newline at end of file diff --git a/content/zh/administration/meta.json b/content/zh/administration/meta.json new file mode 100644 index 000000000..4b640d905 --- /dev/null +++ b/content/zh/administration/meta.json @@ -0,0 +1,11 @@ +{ + "title": "管理", + "defaultOpen": true, + "pages": [ + "[控制台](/zh/administration/console)", + "data", + "protocols", + "cors", + "[虚拟主机访问](/zh/integration/virtual)" + ] +} \ No newline at end of file diff --git a/content/zh/administration/protocols/ftps.md b/content/zh/administration/protocols/ftps.md new file mode 100644 index 000000000..fb8ca5949 --- /dev/null +++ b/content/zh/administration/protocols/ftps.md @@ -0,0 +1,246 @@ +--- +title: "FTP(S)" +description: "配置 RustFS FTP 或 FTPS 网关,并使用 FTP 客户端管理存储桶和对象。" +--- + +RustFS 包含一个 FTP 网关,向标准 FTP 客户端公开存储桶和对象。可以将其作为未加密 FTP 运行,用于隔离的本地测试;也可以作为基于 TLS 的显式 FTP(FTPS)运行,以提供加密连接。RustFS 使用身份与访问管理(IAM)凭证验证每个会话,并将用户的 S3 策略应用于存储操作。 + +标准 RustFS 二进制文件中已编译 FTP 和 FTPS 支持,但两个监听器在运行时均默认禁用。只启用需要使用的监听器。 + +## 概述 + +网关将 FTP 路径映射到 RustFS 资源: + +| FTP 路径 | RustFS 资源 | +| --- | --- | +| `/` | 已验证身份的用户可见的所有存储桶 | +| `/my-bucket/` | `my-bucket` 存储桶 | +| `/my-bucket/hello.txt` | `my-bucket` 中的 `hello.txt` 对象 | + +支持以下 FTP 操作: + +| FTP 命令 | 操作 | +| --- | --- | +| `LIST` | 列出根目录下的存储桶,或存储桶中的对象和前缀 | +| `MKD` | 创建存储桶 | +| `CWD` | 进入存储桶 | +| `STOR` | 上传对象 | +| `RETR` | 下载对象 | +| `DELE` | 删除对象 | +| `RMD` | 递归删除存储桶及其中的对象 | + +RustFS 目前不支持 FTP 重命名操作,也不支持向现有对象追加内容。由于 S3 存储没有原生工作目录或 POSIX 目录模型,某些客户端特定的文件系统操作可能与传统 FTP 服务器不同。 + +将 RustFS 访问密钥作为 FTP 用户名,将其秘密密钥作为密码。无效的用户名和密码都会返回 `530 Not logged in`。登录后,RustFS 会针对每项操作检查 IAM 用户的 S3 权限。 + +:::danger[纯 FTP 会暴露凭证] + +FTP 以未加密方式发送凭证和数据。纯 FTP 只能绑定到回环接口或隔离的测试网络。所有远程或生产连接都应使用 FTPS。 + +::: + +:::warning[存储桶删除是递归操作] + +当前 `RMD` 实现会先删除目标存储桶中的对象,再删除存储桶。在 FTP 客户端中运行 `rmdir` 前请确认路径。 + +::: + +## 配置 + +FTP 和 FTPS 使用不同的监听器和环境变量。 + +### FTP 变量 + +| 变量 | 说明 | 默认值 | +| --- | --- | --- | +| `RUSTFS_FTP_ENABLE` | 启用未加密 FTP 监听器。 | `false` | +| `RUSTFS_FTP_ADDRESS` | FTP 控制连接的绑定地址。 | `0.0.0.0:8021` | +| `RUSTFS_FTP_PASSIVE_PORTS` | `start-end` 格式的闭区间被动数据端口范围。 | `40000-50000` | +| `RUSTFS_FTP_EXTERNAL_IP` | RustFS 位于 NAT 后时向被动客户端公布的公共 IP 或主机名。 | 未设置 | + +### FTPS 变量 + +| 变量 | 说明 | 默认值 | +| --- | --- | --- | +| `RUSTFS_FTPS_ENABLE` | 启用显式 FTPS 监听器。 | `false` | +| `RUSTFS_FTPS_ADDRESS` | FTPS 控制连接的绑定地址。 | `0.0.0.0:8022` | +| `RUSTFS_FTPS_TLS_ENABLED` | 在 FTPS 监听器上启用 TLS。使用 FTPS 时保持启用。 | `true` | +| `RUSTFS_FTPS_CERTS_DIR` | 包含 FTPS 证书和私钥的目录。FTPS 必需。 | 未设置 | +| `RUSTFS_FTPS_PASSIVE_PORTS` | `start-end` 格式的闭区间被动数据端口范围。 | `40000-50000` | +| `RUSTFS_FTPS_EXTERNAL_IP` | RustFS 位于 NAT 后时向被动客户端公布的公共 IP 或主机名。 | 未设置 | + +标准 RustFS 构建会启用 `ftps` 编译时功能,该功能同时提供 FTP 和 FTPS。如果使用 `--no-default-features` 构建 RustFS,请显式加入该功能: + +```bash +cargo build --release --features ftps +``` + +### 使用 FTP 进行本地测试 + +在回环接口上启动未加密的 FTP 监听器: + +```bash +export RUSTFS_FTP_ENABLE=true +export RUSTFS_FTP_ADDRESS=127.0.0.1:8021 +export RUSTFS_FTP_PASSIVE_PORTS=40000-40010 +export RUSTFS_ACCESS_KEY= +export RUSTFS_SECRET_KEY= + +rustfs /path/to/data +``` + +绑定到 `127.0.0.1` 可阻止远程主机连接未加密的监听器。 + +### 准备测试证书 + +FTPS 要求证书目录中包含 `rustfs_cert.pem` 和 `rustfs_key.pem`。本地测试时,创建一个短期自签名证书: + +```bash +mkdir -p /path/to/ftps-certs + +openssl req -x509 -newkey rsa:2048 -nodes \ + -keyout /path/to/ftps-certs/rustfs_key.pem \ + -out /path/to/ftps-certs/rustfs_cert.pem \ + -days 7 \ + -subj "/CN=localhost" \ + -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" +``` + +生产环境请使用受信任证书颁发机构签发的证书。防止未经授权访问 `rustfs_key.pem`,并确保证书使用者可选名称与客户端使用的主机匹配。 + +### 启动 FTPS + +配置显式 FTPS 监听器: + +```bash +export RUSTFS_FTPS_ENABLE=true +export RUSTFS_FTPS_ADDRESS=0.0.0.0:8022 +export RUSTFS_FTPS_TLS_ENABLED=true +export RUSTFS_FTPS_CERTS_DIR=/path/to/ftps-certs +export RUSTFS_FTPS_PASSIVE_PORTS=40000-50000 + +rustfs /path/to/data +``` + +RustFS 要求 FTPS 控制和数据通道都使用 TLS。将客户端配置为 **explicit FTP over TLS**,有时也称为 **FTPES** 或 **Require explicit FTP over TLS**。此监听器未实现隐式 FTPS 模式。 + +如果证书目录未设置、不存在或不包含可用的证书和密钥,FTPS 初始化会失败。有关常规证书指南,请参阅[配置 TLS](/integration/tls-configured)。 + +### 配置被动连接 + +FTP 使用控制端口发送命令,并使用单独的数据连接传输目录列表和文件。对于被动模式: + +1. 允许传入 TCP 流量访问已配置的控制端口。 +2. 允许传入 TCP 流量访问已配置被动范围内的每个端口。 +3. 客户端通过 NAT 或负载均衡器连接时,设置 `RUSTFS_FTP_EXTERNAL_IP` 或 `RUSTFS_FTPS_EXTERNAL_IP`。 + +例如,NAT 后的 FTPS 服务器可以公布其公共主机名: + +```bash +export RUSTFS_FTPS_EXTERNAL_IP=storage.example.com +export RUSTFS_FTPS_PASSIVE_PORTS=40000-40100 +``` + +纯 FTP 监听器请使用对应的 FTP 前缀变量。RustFS 同时支持主动和被动传输模式,但被动模式通常更容易穿过客户端防火墙。 + +## 使用 + +示例使用 [`lftp`](https://lftp.yar.ru/) 以及规范的 `my-bucket` 和 `hello.txt` 名称。IAM 用户必须具有每项操作所需的 S3 权限。 + +### 使用 FTP 连接 + +纯 FTP 只能连接回环测试监听器: + +```bash +lftp -u ftp://127.0.0.1:8021 +``` + +当 `lftp` 提示输入密码时,请输入秘密密钥。 + +### 使用 FTPS 连接 + +连接到显式 FTPS 监听器,并要求控制和数据连接加密: + +```bash +lftp -u -e ' + set ftp:ssl-force true; + set ftp:ssl-protect-data true; + open ftp://storage.example.com:8022 +' +``` + +出现提示时输入秘密密钥。生产环境应保持启用证书验证。 + +仅针对自签名本地测试证书,连接到 `localhost` 并为该会话禁用证书验证: + +```bash +lftp -u -e ' + set ftp:ssl-force true; + set ftp:ssl-protect-data true; + set ssl:verify-certificate no; + open ftp://localhost:8022 +' +``` + +:::warning + +不要在生产环境中禁用证书验证。请改为在客户端信任库中安装签发 CA。 + +::: + +### 列出存储桶并创建存储桶 + +在 `lftp` 提示符下,列出可见存储桶并创建 `my-bucket`: + +```text +lftp> cls -1 / +lftp> mkdir my-bucket +lftp> cd my-bucket +``` + +存储桶名称必须遵循与通过 S3 API 创建的存储桶相同的命名规则。 + +### 上传和下载对象 + +上传 `/path/to/hello.txt`、列出存储桶并下载对象: + +```text +lftp> put /path/to/hello.txt -o hello.txt +lftp> ls +lftp> get hello.txt -o hello.txt +``` + +上传会替换具有相同键的对象。不支持向现有对象追加内容。 + +### 删除对象和存储桶 + +删除对象,返回根目录,然后删除存储桶: + +```text +lftp> rm hello.txt +lftp> cd / +lftp> rmdir my-bucket +``` + +请注意,`rmdir` 会先递归删除存储桶中剩余的对象,再删除存储桶。 + +### 连接其他客户端 + +在 FileZilla 或 Cyberduck 等图形 FTP 客户端中使用以下设置: + +| 设置 | FTP 测试监听器 | FTPS 监听器 | +| --- | --- | --- | +| 协议 | FTP | FTP over TLS (explicit) | +| 主机 | `127.0.0.1` | FTPS 主机名 | +| 端口 | `8021` | `8022` | +| 用户名 | RustFS 访问密钥 | RustFS 访问密钥 | +| 密码 | RustFS 秘密密钥 | RustFS 秘密密钥 | +| 传输模式 | 被动 | 被动 | + +如果登录成功但目录列表或传输超时,请先检查被动端口防火墙规则和外部 IP 设置。 + +## 后续步骤 + +- [管理凭证](/operations/credentials) +- [配置 TLS](/integration/tls-configured) +- [检查服务状态](/operations/status-check) diff --git a/content/zh/administration/protocols/meta.json b/content/zh/administration/protocols/meta.json new file mode 100644 index 000000000..3421bf549 --- /dev/null +++ b/content/zh/administration/protocols/meta.json @@ -0,0 +1,10 @@ +{ + "title": "协议支持", + "pages": [ + "s3", + "webdav", + "ftps", + "sftp", + "[MCP 服务器](/zh/developer/mcp)" + ] +} \ No newline at end of file diff --git a/content/zh/administration/protocols/s3.md b/content/zh/administration/protocols/s3.md new file mode 100644 index 000000000..d4f4352e6 --- /dev/null +++ b/content/zh/administration/protocols/s3.md @@ -0,0 +1,200 @@ +--- +title: "S3" +description: "配置并使用 RustFS S3 兼容 API,以及 AWS CLI、AWS SDK 和其他 S3 客户端。" +--- + +RustFS 为常见对象存储工作负载提供 S3 兼容 REST API。它支持 AWS Signature Version 4(SigV4);正确配置 RustFS 端点、区域、凭证和寻址方式后,可配合 AWS CLI、AWS SDK 和其他 S3 客户端使用。 + +## 概述 + +S3 将数据组织为存储桶和对象。使用默认的路径式寻址时,RustFS URL 与存储的映射如下: + +```text +http://localhost:9000/my-bucket/path/to/hello.txt + | bucket | |---- object key ----| +``` + +RustFS 涵盖应用、备份工具和 SDK 常用的 S3 数据平面: + +| 领域 | 支持的工作流 | +| --- | --- | +| 存储桶 | 创建、删除、列出、检查和获取位置 | +| 对象 | 放置、获取、查看元数据、复制、删除、批量删除、范围读取、条件请求和用户元数据 | +| 列出 | `ListObjects`、`ListObjectsV2`、前缀、分隔符、标记和分页 | +| 大型对象 | 创建、上传、复制、列出、完成和中止分段上传 | +| 数据管理 | 版本控制、生命周期规则、存储桶和对象标签、校验和及对象锁定 | +| 访问控制 | IAM 凭证和策略、存储桶策略、公共访问阻止及预签名 GET/PUT URL | +| 集成 | CORS、存储桶通知、复制配置和服务器端加密工作流 | + +已验证身份的客户端使用访问密钥和秘密密钥为请求签名。匿名请求根据适用的存储桶策略进行评估。 + +:::note[兼容性范围] + +RustFS 为受支持的功能提供广泛的 S3 API 兼容性,但与每个 AWS S3 或 MinIO API 并不完全相同。依赖高级或供应商特定行为前,请查看[已知兼容性差异](#known-compatibility-differences),并针对目标 RustFS 版本进行验证。 + +::: + +## 配置 + +S3 API 在 RustFS 主监听器上启用,不需要单独的协议开关。 + +| 变量 | 用途 | 默认值 | +| --- | --- | --- | +| `RUSTFS_ADDRESS` | S3 API 绑定地址 | `:9000` | +| `RUSTFS_REGION` | 用于请求签名和区域感知客户端的区域 | `us-east-1` | +| `RUSTFS_ACCESS_KEY` | 根访问密钥 | 因安装而异 | +| `RUSTFS_SECRET_KEY` | 根秘密密钥 | 因安装而异 | +| `RUSTFS_SERVER_DOMAINS` | 用于虚拟主机式请求的逗号分隔域名 | 未设置 | +| `RUSTFS_TLS_PATH` | 包含 `rustfs_cert.pem` 和 `rustfs_key.pem` 的目录 | 未设置 | + +应用应使用 IAM 用户或服务账户,而不是根凭证,并且只授予所需的 S3 操作权限。 + +### 路径式寻址 + +路径式寻址是默认方式,不需要 DNS 配置。存储桶名称是请求路径的第一个组成部分: + +```text +http://localhost:9000/my-bucket/hello.txt +``` + +客户端配置如下: + +- 端点:`http://localhost:9000` +- 区域:`us-east-1` +- 访问密钥:`` +- 秘密密钥:`` +- 寻址方式:路径式 + +有些客户端默认使用虚拟主机式请求。请启用其路径式选项,例如 AWS SDK 配置中的 `force_path_style=true` 或 Terraform 中的 `s3_use_path_style = true`。 + +### 虚拟主机式寻址 + +虚拟主机式寻址将存储桶名称放在主机名中。将 `RUSTFS_SERVER_DOMAINS` 设置为 RustFS 应识别的每个基础域名: + +```bash +export RUSTFS_SERVER_DOMAINS="s3.example.com" +``` + +之后,同一对象的地址为: + +```text +https://my-bucket.s3.example.com/hello.txt +``` + +配置通配符 DNS(如 `*.s3.example.com`),使其解析到 RustFS 端点。使用 HTTPS 时,证书也必须覆盖存储桶主机名。名称中带点的存储桶可能需要显式证书名称,因为单标签通配符无法跨越多个标签。 + +:::warning[配置服务器域名] + +除非已配置 `RUSTFS_SERVER_DOMAINS`,否则不要发送虚拟主机式请求。否则 RustFS 会将请求视为路径式,无法从主机名中提取存储桶。 + +::: + +### TLS 和网络访问 + +生产环境请将 `RUSTFS_TLS_PATH` 设置为包含 `rustfs_cert.pem` 和 `rustfs_key.pem` 的目录,然后使用 `https://` 端点。确保客户端信任签发证书的证书颁发机构。 + +在主机防火墙和负载均衡器上允许已配置的 S3 API 端口。默认端口为 TCP `9000`;此监听器也承载 RustFS 管理和节点间流量,因此不要在缺少适当网络和 IAM 控制的情况下允许匿名访问。 + +## 使用 + +以下示例使用 AWS CLI 和规范的本地端点。继续前请安装并配置 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。 + +### 配置 AWS CLI + +```bash +aws configure +``` + +根据提示输入以下值: + +```text +AWS Access Key ID [None]: +AWS Secret Access Key [None]: +Default region name [None]: us-east-1 +Default output format [None]: json +``` + +每条命令都要传入 RustFS 端点。自定义端点可确保这些示例访问 RustFS 而不是 AWS S3。 + +```bash +export RUSTFS_ENDPOINT="http://localhost:9000" +``` + +### 创建和列出存储桶 + +```bash +aws --endpoint-url "$RUSTFS_ENDPOINT" s3api create-bucket \ + --bucket my-bucket + +aws --endpoint-url "$RUSTFS_ENDPOINT" s3api list-buckets +``` + +### 上传和列出对象 + +```bash +printf 'Hello from RustFS\n' > hello.txt + +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp \ + hello.txt s3://my-bucket/path/to/hello.txt + +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 ls \ + s3://my-bucket/path/to/ +``` + +AWS CLI 的传输配置为大型对象选择分段上传时,会自动使用该方式。RustFS 支持标准的创建、上传分段、完成、列出和中止分段上传工作流。 + +### 下载和检查对象 + +```bash +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp \ + s3://my-bucket/path/to/hello.txt ./downloaded-hello.txt + +aws --endpoint-url "$RUSTFS_ENDPOINT" s3api head-object \ + --bucket my-bucket \ + --key path/to/hello.txt +``` + +### 创建预签名 URL + +生成有时间限制的 URL,无需暴露凭证即可下载对象: + +```bash +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 presign \ + s3://my-bucket/path/to/hello.txt \ + --expires-in 3600 +``` + +接收者使用的主机名、方案、端口、区域和对象路径必须与签名 URL 时使用的值匹配。为其他计算机生成 URL 时,请使用可从外部访问的端点。 + +### 删除对象和存储桶 + +```bash +aws --endpoint-url "$RUSTFS_ENDPOINT" s3 rm \ + s3://my-bucket/path/to/hello.txt + +aws --endpoint-url "$RUSTFS_ENDPOINT" s3api delete-bucket \ + --bucket my-bucket +``` + +删除 S3 存储桶前必须将其清空。 + +## 已知兼容性差异 + +当前 RustFS 兼容性测试涵盖上述常见工作流。以下领域与 AWS S3 或 MinIO 不等同: + +- 存储桶访问日志和存储桶所有权控制尚在规划中,未完整实现。 +- ACL 授权有意不受支持。预设 ACL 请求头具有部分兼容性,而 XML 授权策略会返回 `NotImplemented`。请优先使用 IAM 和存储桶策略。 +- 已实现 POST Object 表单上传,但该工作流的校验和处理尚不完整。 +- 某些分段上传列表和分段查找边缘情况不在默认兼容性门禁范围内。 +- S3 Select 目前只接受未压缩输入。 +- 未实现 Access Point 和 Outposts 复制源形式。 +- MinIO 管理 API 是单独的兼容性接口,不能根据 S3 数据平面支持情况推断其兼容性。 + +当工具假设存在 AWS 特定服务、存储类、账户所有权控制或端点发现时,客户端行为也可能不同。请始终显式设置 RustFS 端点,并测试应用使用的确切操作。 + +## 后续步骤 + +- 按照完整的 [AWS CLI 示例](/developer/examples/aws-cli)操作。 +- 选择用于应用集成的 [S3 SDK](/developer/sdk)。 +- 配置[凭证和访问策略](/operations/credentials)。 +- 在可信网络之外开放端点前启用 [TLS](/integration/tls-configured)。 \ No newline at end of file diff --git a/content/zh/administration/protocols/sftp.md b/content/zh/administration/protocols/sftp.md new file mode 100644 index 000000000..dd4c4f64b --- /dev/null +++ b/content/zh/administration/protocols/sftp.md @@ -0,0 +1,181 @@ +--- +title: "SFTP" +description: "构建、配置并使用 RustFS SFTP 网关,通过 SFTP 客户端访问存储桶和对象。" +--- + +RustFS 包含一个 SSH 文件传输协议(SSH File Transfer Protocol,SFTP)网关,通过加密的 SSH 连接向 SFTP 客户端公开存储桶和对象。你可以列出和创建存储桶,以及上传、下载、重命名或删除对象;RustFS 会根据通过身份验证的身份与访问管理(IAM)用户权限执行每项操作。 + +SFTP 是可选的编译时功能,不包含在默认 RustFS 构建中。启用监听器前,请使用 `sftp` 或 `full` 功能构建 RustFS。监听器在运行时默认禁用。 + +## 概述 + +网关将 SFTP 路径映射到 RustFS 资源: + +| SFTP 路径 | RustFS 资源 | +| --- | --- | +| `/` | 已验证身份的用户可见的所有存储桶 | +| `/my-bucket/` | `my-bucket` 存储桶 | +| `/my-bucket/hello.txt` | `my-bucket` 中的 `hello.txt` 对象 | +| `/my-bucket/docs/hello.txt` | `my-bucket` 中的 `docs/hello.txt` 对象 | + +RustFS 通过 SFTP 网关支持以下操作: + +| SFTP 操作 | RustFS 操作 | +| --- | --- | +| 列出 `/` | 列出可见存储桶 | +| 列出存储桶或前缀 | 列出对象和前缀 | +| 在 `/` 下执行 `mkdir` | 创建存储桶 | +| `put` | 上传对象 | +| `get` | 下载对象 | +| `rename` | 复制对象,然后删除源对象 | +| `rm` | 删除对象 | +| 在 `/` 下执行 `rmdir` | 删除空存储桶 | + +在 `/` 的直属位置创建或删除目录,会创建或删除存储桶。存储桶下的目录映射到对象键前缀,不作为独立的文件系统目录存在。 + +将 RustFS 访问密钥作为 SFTP 用户名,将其秘密密钥作为密码。RustFS 会针对每项操作检查 IAM 用户的 S3 策略。 + +:::warning[仅支持密码身份验证] + +SFTP 网关不支持客户端公钥身份验证或匿名访问。SSH 主机密钥用于标识服务器,不用于验证客户端身份。不要为 RustFS SFTP 配置 `authorized_keys` 文件。 + +::: + +## 配置 + +### 构建 SFTP 支持 + +使用 SFTP 功能构建 RustFS: + +```bash +cargo build --release --features sftp +``` + +要启用包括 SFTP 在内的所有可选 RustFS 功能,请改用 `--features full`。在未使用 `sftp` 功能构建的二进制文件中,设置 `RUSTFS_SFTP_ENABLE=true` 不会生效。 + +### SFTP 变量 + +| 变量 | 说明 | 默认值 | +| --- | --- | --- | +| `RUSTFS_SFTP_ENABLE` | 启用 SFTP 监听器。 | `false` | +| `RUSTFS_SFTP_ADDRESS` | SFTP 连接的绑定地址。 | `0.0.0.0:2222` | +| `RUSTFS_SFTP_HOST_KEY_DIR` | 包含至少一个未加密 SSH 私有主机密钥的目录。启用 SFTP 时必需。 | 未设置 | +| `RUSTFS_SFTP_READ_ONLY` | 拒绝修改存储桶或对象的操作。 | `false` | +| `RUSTFS_SFTP_IDLE_TIMEOUT` | SSH 不活动超时秒数。必须大于零。 | `600` | +| `RUSTFS_SFTP_PART_SIZE` | 分段上传的分段大小(字节)。 | `16777216` (16 MiB) | + +默认端口 `2222` 避免使用特权 SSH 端口 `22`。地址可以使用 IPv4 或 IPv6 语法,例如 `127.0.0.1:2222` 或 `[::]:2222`。 + +### 准备主机密钥 + +创建持久主机密钥目录并生成 Ed25519 主机密钥: + +```bash +mkdir -p /path/to/sftp-keys +ssh-keygen -t ed25519 \ + -f /path/to/sftp-keys/ssh_host_ed25519_key \ + -N "" +chmod 600 /path/to/sftp-keys/ssh_host_ed25519_key* +``` + +主机密钥不能使用密码短语。RustFS 也接受可解码的 ECDSA 和 RSA 私有主机密钥。 + +在 Unix 上,主机密钥目录中的每个常规文件必须只能由其所有者访问。`ssh-keygen` 命令还会创建 `.pub` 文件;可以按上述方式保留仅限所有者的权限,也可以将其删除,因为 RustFS 不会读取该文件。如果目录缺失、不包含可用私钥,或包含设置了组或其他用户权限位的常规文件,RustFS 会拒绝启动。 + +:::warning[保护主机密钥] + +重启后应继续使用相同的主机密钥,以便客户端验证服务器身份。将访问权限限制到运行 RustFS 的账户,并安全备份密钥。主机密钥发生变化会导致客户端显示可能存在中间人攻击的警告。 + +::: + +### 启动 SFTP 监听器 + +以下示例在回环接口上启动 SFTP,用于本地测试: + +```bash +export RUSTFS_SFTP_ENABLE=true +export RUSTFS_SFTP_ADDRESS=127.0.0.1:2222 +export RUSTFS_SFTP_HOST_KEY_DIR=/path/to/sftp-keys +export RUSTFS_ACCESS_KEY= +export RUSTFS_SECRET_KEY= + +rustfs /path/to/data +``` + +对于远程连接,请绑定到合适的网络接口,并允许传入 TCP 流量访问已配置的 SFTP 端口。此监听器与 S3 API 和控制台监听器分开。 + +## 使用 + +以下示例使用 OpenSSH `sftp` 客户端、规范的 `my-bucket` 和 `hello.txt` 名称,以及端口 `2222` 上的本地监听器。 + +### 连接 + +```bash +sftp -P 2222 @127.0.0.1 +``` + +出现密码提示时输入 RustFS 秘密密钥。首次连接时,请先验证显示的主机密钥指纹,再接受该密钥。 + +### 列出和创建存储桶 + +在 `sftp` 提示符下,列出 IAM 用户可见的存储桶并创建 `my-bucket`: + +```text +sftp> ls / +sftp> mkdir /my-bucket +sftp> cd /my-bucket +``` + +存储桶名称必须遵循与通过 S3 API 创建的存储桶相同的命名规则。不能直接在 `/` 下创建文件。 + +### 上传和下载对象 + +上传 `/path/to/hello.txt`、列出存储桶并下载对象: + +```text +sftp> put /path/to/hello.txt /my-bucket/hello.txt +sftp> ls /my-bucket +sftp> get /my-bucket/hello.txt hello.txt +``` + +上传必须从文件开头按顺序进行。不支持续传、追加、原地编辑,以及通过多个分段连接上传一个对象。 + +### 重命名对象 + +```text +sftp> rename /my-bucket/hello.txt /my-bucket/greeting.txt +``` + +RustFS 通过服务器端复制后删除源对象来实现重命名。该操作不是原子的,也不支持重命名存储桶。IAM 用户需要读取和删除源对象以及写入目标位置的权限。 + +### 删除对象和存储桶 + +删除对象,然后删除空存储桶: + +```text +sftp> rm /my-bucket/greeting.txt +sftp> rmdir /my-bucket +``` + +RustFS 不会通过 SFTP 递归删除非空存储桶。 + +### 连接桌面客户端 + +在 FileZilla、Cyberduck 或 WinSCP 等图形客户端中使用以下设置: + +| 设置 | 值 | +| --- | --- | +| 协议 | SFTP (SSH File Transfer Protocol) | +| 主机 | RustFS SFTP 主机名 | +| 端口 | `2222`,或 `RUSTFS_SFTP_ADDRESS` 中的端口 | +| 用户名 | RustFS 访问密钥 | +| 密码 | RustFS 秘密密钥 | +| 身份验证 | 密码 | + +将客户端配置为使用单连接上传完整文件。网关将 SFTP 操作映射到对象存储,因此不支持符号链接,也不支持更改 POSIX 所有权、权限或时间戳。 + +## 后续步骤 + +- [管理凭证](/operations/credentials) +- [检查服务状态](/operations/status-check) +- [配置生命周期管理](/administration/data/lifecycle-management) diff --git a/content/zh/administration/protocols/webdav.md b/content/zh/administration/protocols/webdav.md new file mode 100644 index 000000000..9900c4747 --- /dev/null +++ b/content/zh/administration/protocols/webdav.md @@ -0,0 +1,208 @@ +--- +title: "WebDAV" +description: "配置 RustFS WebDAV 网关,并使用 WebDAV 客户端访问存储桶和对象。" +--- + +RustFS 包含一个网络分布式创作与版本控制(Web Distributed Authoring and Versioning,WebDAV)网关,通过 HTTP 或 HTTPS 向 WebDAV 客户端公开存储桶和对象。你可以浏览存储桶、创建集合,以及上传、下载、重命名或删除对象;RustFS 会根据通过身份验证的身份与访问管理(IAM)用户权限执行每项操作。 + +标准 RustFS 二进制文件中已编译 WebDAV 支持,但网关在运行时默认禁用。连接客户端前必须启用并配置网关。 + +## 概述 + +网关将 WebDAV 路径映射到 RustFS 资源: + +| WebDAV 路径 | RustFS 资源 | +| --- | --- | +| `/` | 已验证身份的用户可见的所有存储桶 | +| `/my-bucket/` | `my-bucket` 存储桶 | +| `/my-bucket/hello.txt` | `my-bucket` 中的 `hello.txt` 对象 | +| `/my-bucket/docs/hello.txt` | `my-bucket` 中的 `docs/hello.txt` 对象 | + +RustFS 通过网关支持以下操作: + +| 方法 | 操作 | +| --- | --- | +| `PROPFIND` | 列出存储桶或对象并读取元数据 | +| `MKCOL` | 创建存储桶或目录前缀 | +| `PUT` | 上传对象 | +| `GET` | 下载对象 | +| `HEAD` | 读取对象元数据 | +| `MOVE` | 重命名或移动对象或目录 | +| `DELETE` | 删除对象、目录或存储桶 | + +请使用 `PROPFIND` 而不是 `GET` 列出集合。当前网关会为针对目录的 `GET` 请求返回 `405 Method Not Allowed`。 + +WebDAV 使用 HTTP Basic 身份验证。将 RustFS 访问密钥作为用户名,将其秘密密钥作为密码。网关会根据 RustFS IAM 验证凭证,并将用户的 S3 策略应用于每项操作。 + +:::warning[保护凭证] + +Basic 身份验证不会加密凭证。仅在隔离的本地测试中禁用 TLS。所有远程或生产连接都应使用 HTTPS。 + +::: + +## 配置 + +启动 RustFS 前,使用环境变量配置网关: + +| 变量 | 说明 | 默认值 | +| --- | --- | --- | +| `RUSTFS_WEBDAV_ENABLE` | 启用 WebDAV 网关。 | `false` | +| `RUSTFS_WEBDAV_ADDRESS` | WebDAV 连接的绑定地址。 | `0.0.0.0:8080` | +| `RUSTFS_WEBDAV_TLS_ENABLED` | 为 WebDAV 监听器启用 TLS。 | `true` | +| `RUSTFS_WEBDAV_CERTS_DIR` | RustFS TLS 运行时使用的证书目录。启用 TLS 时必需。 | 未设置 | +| `RUSTFS_WEBDAV_MAX_BODY_SIZE` | 最大请求正文大小(字节)。必须大于零。 | `5368709120` (5 GiB) | + +标准 RustFS 构建会启用 WebDAV 编译时功能。如果使用 `--no-default-features` 构建 RustFS,请显式加入该功能: + +```bash +cargo build --release --features webdav +``` + +### 不使用 TLS 进行本地测试 + +以下示例在端口 `8080` 上启动带 HTTP WebDAV 监听器的 RustFS: + +```bash +export RUSTFS_WEBDAV_ENABLE=true +export RUSTFS_WEBDAV_ADDRESS=127.0.0.1:8080 +export RUSTFS_WEBDAV_TLS_ENABLED=false +export RUSTFS_ACCESS_KEY= +export RUSTFS_SECRET_KEY= + +rustfs /path/to/data +``` + +绑定到 `127.0.0.1` 可阻止其他主机连接未加密的测试端点。 + +### HTTPS + +对于远程或生产连接,请启用 TLS 并提供证书目录: + +```bash +export RUSTFS_WEBDAV_ENABLE=true +export RUSTFS_WEBDAV_ADDRESS=0.0.0.0:8080 +export RUSTFS_WEBDAV_TLS_ENABLED=true +export RUSTFS_WEBDAV_CERTS_DIR=/path/to/certs + +rustfs /path/to/data +``` + +如果启用了 TLS 但未设置 `RUSTFS_WEBDAV_CERTS_DIR`,或该目录不存在,WebDAV 初始化会失败。有关证书准备指南,请参阅[配置 TLS](/integration/tls-configured)。 + +允许传入 TCP 流量访问已配置的 WebDAV 端口。此监听器与 S3 API 和控制台监听器分开。 + +## 使用 + +以下命令使用 HTTP 端点进行本地测试。请将端点和凭证替换为 HTTPS WebDAV 端点,以及具有所需存储桶和对象权限的 IAM 用户。 + +设置可复用的 shell 变量,避免在每条命令中直接放置秘密密钥: + +```bash +export WEBDAV_URL=http://127.0.0.1:8080 +export WEBDAV_USER= +read -s WEBDAV_PASSWORD +export WEBDAV_PASSWORD +``` + +### 列出存储桶 + +发送带 `Depth: 1` 的 `PROPFIND`,列出用户可见的存储桶: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request PROPFIND \ + --header "Depth: 1" \ + "$WEBDAV_URL/" +``` + +### 创建存储桶 + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request MKCOL \ + "$WEBDAV_URL/my-bucket/" +``` + +存储桶名称必须遵循与通过 S3 API 创建的存储桶相同的命名规则。 + +### 上传和下载对象 + +上传 `/path/to/hello.txt`: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --upload-file /path/to/hello.txt \ + "$WEBDAV_URL/my-bucket/hello.txt" +``` + +下载对象: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --output hello.txt \ + "$WEBDAV_URL/my-bucket/hello.txt" +``` + +### 创建和列出目录 + +存储桶下的 WebDAV 目录映射到对象键前缀: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request MKCOL \ + "$WEBDAV_URL/my-bucket/docs/" + +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request PROPFIND \ + --header "Depth: 1" \ + "$WEBDAV_URL/my-bucket/docs/" +``` + +### 重命名对象 + +使用 `MOVE` 和同一 WebDAV 端点上的目标路径: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request MOVE \ + --header "Destination: $WEBDAV_URL/my-bucket/greeting.txt" \ + "$WEBDAV_URL/my-bucket/hello.txt" +``` + +IAM 用户需要读取和删除源对象以及写入目标位置的权限。如果授权失败,RustFS 会保留源对象不变。 + +### 删除对象或存储桶 + +删除对象: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request DELETE \ + "$WEBDAV_URL/my-bucket/greeting.txt" +``` + +删除存储桶中的内容后再删除存储桶: + +```bash +curl --user "$WEBDAV_USER:$WEBDAV_PASSWORD" \ + --request DELETE \ + "$WEBDAV_URL/my-bucket/" +``` + +### 连接桌面客户端 + +在支持 Basic 身份验证的客户端中使用 WebDAV 端点: + +| 客户端 | 连接地址 | +| --- | --- | +| GNOME Files | HTTP 使用 `dav://:8080/`,HTTPS 使用 `davs://:8080/` | +| macOS Finder | `http://:8080/` 或 `https://:8080/` | +| Windows File Explorer | `https://:8080/` | + +客户端提示输入凭证时,请输入 RustFS 访问密钥和秘密密钥。客户端行为和支持的 WebDAV 方法各不相同;排查故障时可使用 `curl` 隔离服务器端错误。 + +## 后续步骤 + +- [管理凭证](/operations/credentials) +- [配置 TLS](/integration/tls-configured) +- [检查服务状态](/operations/status-check) diff --git a/content/zh/developer/examples/aws-cli.md b/content/zh/developer/examples/aws-cli.md new file mode 100644 index 000000000..9225e3b9f --- /dev/null +++ b/content/zh/developer/examples/aws-cli.md @@ -0,0 +1,73 @@ +--- +title: "AWS CLI" +description: "将 AWS CLI 连接到 RustFS,并执行基本对象操作。" +--- + +[AWS CLI](https://docs.aws.amazon.com/cli/) 是 Amazon 官方的 S3 命令行工具,可通过 `--endpoint-url` 标志与 RustFS 配合使用。 + +## 安装 + +请按照[官方安装指南](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)操作;也可以在 macOS 上运行: + +```bash +brew install awscli +``` + +## 配置 + +设置您的[访问密钥](../../security-compliance/iam/access-token.md)和区域: + +```bash +aws configure +``` + +```text +AWS Access Key ID [None]: +AWS Secret Access Key [None]: +Default region name [None]: us-east-1 +Default output format [None]: json +``` + +在每条命令中通过 `--endpoint-url` 传入您的 RustFS 地址。请将 `http://localhost:9000` 替换为您的服务器地址。设置 `--endpoint-url` 后,AWS CLI 会使用 RustFS 所要求的路径样式寻址。 + +:::note + +如果您在安装时未设置凭证,本地测试的默认值为 `rustfsadmin` / `rustfsadmin`,切勿在一次性本地试用之外使用这些凭证。 + +::: + +## 验证 + +创建存储桶: + +```bash +aws s3 mb s3://my-bucket --endpoint-url http://localhost:9000 +``` + +```text +make_bucket: my-bucket +``` + +上传文件: + +```bash +aws s3 cp /path/to/hello.txt s3://my-bucket/ --endpoint-url http://localhost:9000 +``` + +```text +upload: ../path/to/hello.txt to s3://my-bucket/hello.txt +``` + +列出存储桶内容: + +```bash +aws s3 ls s3://my-bucket --endpoint-url http://localhost:9000 +``` + +```text +2026-07-15 10:30:00 12 hello.txt +``` + +## 后续步骤 + +使用 [S3 SDK](../sdk/index.md) 构建与 RustFS 对接的应用程序,或使用 [`rc`](/operations/rc) 管理对象。 \ No newline at end of file diff --git a/content/zh/developer/examples/aws-sdk-go.md b/content/zh/developer/examples/aws-sdk-go.md new file mode 100644 index 000000000..b589f16dd --- /dev/null +++ b/content/zh/developer/examples/aws-sdk-go.md @@ -0,0 +1,55 @@ +--- +title: "AWS SDK for Go" +description: "将 AWS SDK for Go v2 连接到 RustFS,并执行基本对象操作。" +--- + +[AWS SDK for Go v2](https://aws.github.io/aws-sdk-go-v2/docs/) 可通过自定义基础端点连接到 RustFS。下面是最简连接方法;如需完整程序,请参阅 [Go SDK 指南](../sdk/go.md)。 + +## 安装 + +```bash +go get github.com/aws/aws-sdk-go-v2/aws +go get github.com/aws/aws-sdk-go-v2/credentials +go get github.com/aws/aws-sdk-go-v2/service/s3 +``` + +## 配置 + +请将 `http://localhost:9000` 替换为您的服务器地址,并使用您自己的[访问密钥](../../security-compliance/iam/access-token.md)。RustFS 要求使用路径样式寻址 (`UsePathStyle: true`): + +```go {9,11} +import ( + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +cfg := aws.Config{ + Region: "us-east-1", + Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider("", "", "")), +} +client := s3.NewFromConfig(cfg, func(o *s3.Options) { + o.BaseEndpoint = aws.String("http://localhost:9000") + o.UsePathStyle = true +}) +``` + +## 验证 + +```go +ctx := context.Background() +client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: aws.String("my-bucket")}) + +out, _ := client.ListBuckets(ctx, &s3.ListBucketsInput{}) +for _, b := range out.Buckets { + fmt.Println(*b.Name) +} +``` + +```text +my-bucket +``` + +## 后续步骤 + +请参阅完整的 [Go SDK 指南](../sdk/go.md),或使用 [`rc`](/operations/rc) 管理对象。 \ No newline at end of file diff --git a/content/zh/developer/examples/aws-sdk-js.md b/content/zh/developer/examples/aws-sdk-js.md new file mode 100644 index 000000000..3cc553e95 --- /dev/null +++ b/content/zh/developer/examples/aws-sdk-js.md @@ -0,0 +1,46 @@ +--- +title: "AWS SDK for JavaScript" +description: "将 AWS SDK for JavaScript v3 连接到 RustFS,并通过 Node.js 执行基本对象操作。" +--- + +[AWS SDK for JavaScript v3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/) 可通过自定义端点连接到 RustFS。下面是最简连接方法;如需完整程序,请参阅 [JavaScript SDK 指南](../sdk/javascript.md)。 + +## 安装 + +```bash +npm install @aws-sdk/client-s3 +``` + +## 配置 + +请将 `http://localhost:9000` 替换为您的服务器地址,并使用您自己的[访问密钥](../../security-compliance/iam/access-token.md)。RustFS 要求使用路径样式寻址 (`forcePathStyle: true`): + +```javascript title="index.mjs" {8} +import { S3Client, CreateBucketCommand, PutObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3"; +import { readFileSync } from "node:fs"; + +const s3 = new S3Client({ + endpoint: "http://localhost:9000", + region: "us-east-1", + credentials: { accessKeyId: "", secretAccessKey: "" }, + forcePathStyle: true, +}); +``` + +## 验证 + +```javascript +await s3.send(new CreateBucketCommand({ Bucket: "my-bucket" })); +await s3.send(new PutObjectCommand({ Bucket: "my-bucket", Key: "hello.txt", Body: readFileSync("/path/to/hello.txt") })); + +const out = await s3.send(new ListObjectsV2Command({ Bucket: "my-bucket" })); +for (const obj of out.Contents ?? []) console.log(obj.Key, obj.Size); +``` + +```text +hello.txt 12 +``` + +## 后续步骤 + +请参阅完整的 [JavaScript SDK 指南](../sdk/javascript.md),或使用 [`rc`](/operations/rc) 管理对象。 \ No newline at end of file diff --git a/content/zh/developer/examples/boto3.md b/content/zh/developer/examples/boto3.md new file mode 100644 index 000000000..66968590c --- /dev/null +++ b/content/zh/developer/examples/boto3.md @@ -0,0 +1,53 @@ +--- +title: "boto3 (Python)" +description: "将 boto3 连接到 RustFS,并通过 Python 执行基本对象操作。" +--- + +[boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html) 是适用于 Python 的 AWS SDK,可通过自定义端点连接到 RustFS。 + +## 安装 + +```bash +pip install boto3 +``` + +## 配置 + +将客户端指向您的 RustFS 端点。请将 `http://localhost:9000` 替换为您的服务器地址,并使用您自己的[访问密钥](../../security-compliance/iam/access-token.md)。RustFS 要求使用路径样式寻址,可通过 botocore `Config` 进行设置: + +```python +import boto3 +from botocore.config import Config + +s3 = boto3.client( + "s3", + endpoint_url="http://localhost:9000", + aws_access_key_id="", + aws_secret_access_key="", + region_name="us-east-1", + config=Config(s3={"addressing_style": "path"}), +) +``` + +## 验证 + +创建存储桶、上传文件并列出存储桶中的对象: + +```python +s3.create_bucket(Bucket="my-bucket") + +s3.upload_file("/path/to/hello.txt", "my-bucket", "hello.txt") + +for obj in s3.list_objects_v2(Bucket="my-bucket").get("Contents", []): + print(obj["Key"], obj["Size"]) +``` + +预期输出: + +```text +hello.txt 12 +``` + +## 后续步骤 + +有关更多编程语言,请参阅 [S3 SDK 概述](../sdk/index.md);也可以使用 [`rc`](/operations/rc) 管理对象。 \ No newline at end of file diff --git a/content/zh/developer/examples/meta.json b/content/zh/developer/examples/meta.json new file mode 100644 index 000000000..8ae3c3a58 --- /dev/null +++ b/content/zh/developer/examples/meta.json @@ -0,0 +1,13 @@ +{ + "title": "示例", + "pages": [ + "[rc](/zh/operations/rc)", + "[AWS CLI](/zh/developer/examples/aws-cli)", + "[s3cmd](/zh/developer/examples/s3cmd)", + "[rclone](/zh/developer/examples/rclone)", + "[boto3 (Python)](/zh/developer/examples/boto3)", + "[AWS SDK(JavaScript)](/zh/developer/examples/aws-sdk-js)", + "[AWS SDK(Go)](/zh/developer/examples/aws-sdk-go)", + "[Terraform](/zh/developer/examples/terraform)" + ] +} diff --git a/content/zh/developer/examples/rclone.md b/content/zh/developer/examples/rclone.md new file mode 100644 index 000000000..b77c964f3 --- /dev/null +++ b/content/zh/developer/examples/rclone.md @@ -0,0 +1,59 @@ +--- +title: "rclone" +description: "将 rclone 连接到 RustFS,并执行基本对象操作。" +--- + +[rclone](https://rclone.org/) 是一个用于在云存储中同步文件的命令行程序,支持 RustFS 实现的 S3 协议。 + +## 安装 + +```bash +curl https://rclone.org/install.sh | sudo bash +``` + +也可以参阅[官方安装指南](https://rclone.org/install/)。 + +## 配置 + +在 `~/.config/rclone/rclone.conf` 中添加远程存储。请将 `http://localhost:9000` 替换为您的服务器地址,并使用您自己的[访问密钥](../../security-compliance/iam/access-token.md)。RustFS 使用路径样式寻址,因此必须设置 `force_path_style = true`: + +```ini title="~/.config/rclone/rclone.conf" +[rustfs] +type = s3 +provider = Other +access_key_id = +secret_access_key = +endpoint = http://localhost:9000 +region = us-east-1 +force_path_style = true +``` + +## 验证 + +创建存储桶: + +```bash +rclone mkdir rustfs:my-bucket +``` + +上传文件: + +```bash +rclone copy /path/to/hello.txt rustfs:my-bucket +``` + +列出存储桶及其内容: + +```bash +rclone lsd rustfs: +rclone ls rustfs:my-bucket +``` + +```text + -1 2026-07-15 10:30:00 -1 my-bucket + 12 hello.txt +``` + +## 后续步骤 + +使用 [S3 SDK](../sdk/index.md) 构建与 RustFS 对接的应用程序,或使用 [`rc`](/operations/rc) 管理对象。 \ No newline at end of file diff --git a/content/zh/developer/examples/s3cmd.md b/content/zh/developer/examples/s3cmd.md new file mode 100644 index 000000000..d398bb2c1 --- /dev/null +++ b/content/zh/developer/examples/s3cmd.md @@ -0,0 +1,56 @@ +--- +title: "s3cmd" +description: "将 s3cmd 连接到 RustFS,并从命令行执行基本对象操作。" +--- + +[s3cmd](https://s3tools.org/s3cmd) 是适用于 S3 兼容存储的命令行客户端。使用一个简短的配置文件即可将其指向您的 RustFS 端点。 + +## 安装 + +```bash +# macOS +brew install s3cmd +# Debian/Ubuntu +sudo apt install s3cmd +# or via pip +pip install s3cmd +``` + +## 配置 + +创建 `~/.s3cfg`。请将 `localhost:9000` 替换为您的服务器地址,并使用您自己的[访问密钥](../../security-compliance/iam/access-token.md)。RustFS 使用路径样式寻址,因此请将存储桶主机设置为相同端点: + +```ini title="~/.s3cfg" +[default] +access_key = +secret_key = +host_base = localhost:9000 +host_bucket = localhost:9000 +use_https = False +signature_v2 = False +``` + +:::note + +如果您已[配置 TLS](../../integration/tls-configured.md),请设置 `use_https = True` 并指向端口 `9000`。 + +::: + +## 验证 + +创建存储桶、上传文件并列出其内容: + +```bash +s3cmd mb s3://my-bucket +s3cmd put /path/to/hello.txt s3://my-bucket/hello.txt +s3cmd ls s3://my-bucket +``` + +```text +upload: '/path/to/hello.txt' -> 's3://my-bucket/hello.txt' [1 of 1] +2026-07-16 10:00 12 s3://my-bucket/hello.txt +``` + +## 后续步骤 + +请参阅 [SDK 概述](../sdk/index.md)以连接应用程序,或使用 [`rc`](/operations/rc) 管理对象。 \ No newline at end of file diff --git a/content/zh/developer/examples/terraform.md b/content/zh/developer/examples/terraform.md new file mode 100644 index 000000000..1a88233eb --- /dev/null +++ b/content/zh/developer/examples/terraform.md @@ -0,0 +1,56 @@ +--- +title: "Terraform" +description: "使用指向自定义端点的 AWS provider,通过 Terraform 管理 RustFS 存储桶和对象。" +--- + +将 [Terraform AWS provider](https://registry.terraform.io/providers/hashicorp/aws/latest) 的 S3 端点指向您的服务器并启用路径样式寻址后,即可与 RustFS 配合使用。 + +## 配置 + +请将 `http://localhost:9000` 替换为您的服务器地址,并使用您自己的[访问密钥](../../security-compliance/iam/access-token.md)。这些 skip 标志会阻止 provider 调用仅适用于 AWS 的元数据和 STS 端点: + +```hcl title="main.tf" +provider "aws" { + access_key = "" + secret_key = "" + region = "us-east-1" + s3_use_path_style = true + skip_credentials_validation = true + skip_metadata_api_check = true + skip_requesting_account_id = true + + endpoints { + s3 = "http://localhost:9000" + } +} + +resource "aws_s3_bucket" "demo" { + bucket = "my-bucket" +} + +resource "aws_s3_object" "hello" { + bucket = aws_s3_bucket.demo.id + key = "hello.txt" + source = "/path/to/hello.txt" +} +``` + +## 应用 + +```bash +terraform init +terraform apply +``` + +```text +Plan: 2 to add, 0 to change, 0 to destroy. +... +aws_s3_bucket.demo: Creation complete after 0s [id=my-bucket] +aws_s3_object.hello: Creation complete after 0s [id=hello.txt] + +Apply complete! Resources: 2 added, 0 changed, 0 destroyed. +``` + +## 后续步骤 + +请参阅 [SDK 概述](../sdk/index.md)以连接应用程序,或参阅 [AWS CLI 示例](aws-cli.md)执行临时命令。 \ No newline at end of file diff --git a/content/zh/developer/images/add-rustfs-mcp-succ.png b/content/zh/developer/images/add-rustfs-mcp-succ.png new file mode 100644 index 000000000..c321d3c7b Binary files /dev/null and b/content/zh/developer/images/add-rustfs-mcp-succ.png differ diff --git a/content/zh/developer/images/list-rustfs-bucket-with-mcp.png b/content/zh/developer/images/list-rustfs-bucket-with-mcp.png new file mode 100644 index 000000000..f59e288cf Binary files /dev/null and b/content/zh/developer/images/list-rustfs-bucket-with-mcp.png differ diff --git a/content/zh/developer/index.md b/content/zh/developer/index.md new file mode 100644 index 000000000..ceffcec6b --- /dev/null +++ b/content/zh/developer/index.md @@ -0,0 +1,12 @@ +--- +title: 开发者 +description: "使用 STS、MCP、SDK 和 S3 兼容 API 将应用程序与 RustFS 集成。" +--- + +使用本节提供的临时凭证、模型上下文协议 (MCP)、SDK 和 S3 兼容 API,将应用程序与 RustFS 集成。 + +- [安全令牌服务 (STS)](/security-compliance/iam/sts) 介绍如何请求临时凭证。 +- [MCP](/developer/mcp) 将 AI 工具和智能体连接到 RustFS。 +- [SDK](/developer/sdk) 提供特定于编程语言的集成示例。 +- [集成指南](/developer/integration) 涵盖代理和数据平台。 +- [S3 API](/administration/protocols/s3) 介绍客户端配置和兼容性注意事项。 \ No newline at end of file diff --git a/content/zh/developer/integration/big-data/iceberg.md b/content/zh/developer/integration/big-data/iceberg.md new file mode 100644 index 000000000..bb45f4450 --- /dev/null +++ b/content/zh/developer/integration/big-data/iceberg.md @@ -0,0 +1,271 @@ +--- +title: "Apache Iceberg" +description: "使用 Docker Compose 运行 Apache Iceberg、Spark、REST catalog 和 RustFS 对象存储。" +--- + +本指南将运行 **Apache Iceberg**、Spark、Iceberg REST catalog,并将 **RustFS** 用作兼容 S3 的仓库。你将创建一个 Iceberg 表、写入并查询数据行,然后验证表文件是否存储在 RustFS 中。 + +你需要安装带 Compose 插件的 Docker,并具备足够的本地资源来运行四个容器。此部署仅用于本地集成测试,不适用于生产环境。 + +:::note[上游状态] + +Apache Iceberg [PR #14928](https://github.com/apache/iceberg/pull/14928) 展示了相同的 Spark、REST catalog、`S3FileIO` 和 RustFS 工作流,包括表创建与写入。该拉取请求已关闭且未合并,当前的 [Spark 快速入门](https://iceberg.apache.org/spark-quickstart/#docker-compose) 仍使用另一种兼容 S3 的存储。因此,以下配置记录的是 RustFS 集成方式,而不是 Apache Iceberg 的默认配置。 + +::: + +## 架构 + +```mermaid +flowchart LR + Spark["Spark SQL"] -->|REST catalog API| Catalog["Iceberg REST catalog"] + Spark -->|S3FileIO| RustFS["RustFS S3 API"] + Catalog -->|S3FileIO| RustFS + Init["Bucket initializer"] -->|Create my-bucket| RustFS +``` + +Spark 使用 REST 服务执行 catalog 操作。Spark 和 REST catalog 都会接收 RustFS 端点、区域、凭证和路径样式设置,以便访问 `s3://my-bucket/warehouse` 中的元数据和数据文件。 + +## 1. 创建项目文件 + +创建工作目录: + +```bash +mkdir rustfs-iceberg +cd rustfs-iceberg +``` + +创建环境文件并替换两个凭证占位符: + +```ini title=".env" +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +``` + +请为仓库存储桶使用专用凭证。不要将 `.env` 提交到源代码管理系统。 + +创建 Spark catalog 配置: + +```ini title="spark-defaults.conf" +spark.sql.extensions org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions +spark.sql.catalog.demo org.apache.iceberg.spark.SparkCatalog +spark.sql.catalog.demo.type rest +spark.sql.catalog.demo.uri http://rest:8181 +spark.sql.catalog.demo.io-impl org.apache.iceberg.aws.s3.S3FileIO +spark.sql.catalog.demo.warehouse s3://my-bucket/warehouse +spark.sql.catalog.demo.s3.endpoint http://rustfs:9000 +spark.sql.catalog.demo.s3.path-style-access true +spark.sql.defaultCatalog demo +spark.sql.catalogImplementation in-memory +``` + +此容器网络端点必须使用路径样式访问。主机名 `rustfs` 只能在 Compose 网络内部解析;在主机上运行的客户端应改用 `http://localhost:9000`。 + +创建 Compose 文件: + +```yaml title="compose.yaml" +services: + rustfs: + image: rustfs/rustfs:1.0.0-alpha.83 + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + RUSTFS_VOLUMES: /data + RUSTFS_ADDRESS: 0.0.0.0:9000 + RUSTFS_CONSOLE_ADDRESS: 0.0.0.0:9001 + RUSTFS_CONSOLE_ENABLE: "true" + volumes: + - rustfs-data:/data + ports: + - "9000:9000" + - "9001:9001" + networks: + - iceberg + + create-bucket: + image: rustfs/rc:latest + depends_on: + - rustfs + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + entrypoint: + - /bin/sh + - -c + - | + until /usr/bin/rc alias set rustfs http://rustfs:9000 "$${RUSTFS_ACCESS_KEY}" "$${RUSTFS_SECRET_KEY}"; do + echo "Waiting for RustFS..." + sleep 2 + done + /usr/bin/rc ls rustfs/my-bucket >/dev/null 2>&1 || /usr/bin/rc mb rustfs/my-bucket + networks: + - iceberg + + rest: + image: apache/iceberg-rest-fixture + depends_on: + create-bucket: + condition: service_completed_successfully + environment: + AWS_ACCESS_KEY_ID: ${RUSTFS_ACCESS_KEY} + AWS_SECRET_ACCESS_KEY: ${RUSTFS_SECRET_KEY} + AWS_REGION: us-east-1 + CATALOG_WAREHOUSE: s3://my-bucket/warehouse + CATALOG_IO__IMPL: org.apache.iceberg.aws.s3.S3FileIO + CATALOG_S3_ENDPOINT: http://rustfs:9000 + CATALOG_S3_PATH__STYLE__ACCESS: "true" + ports: + - "8181:8181" + networks: + - iceberg + + spark-iceberg: + image: tabulario/spark-iceberg + depends_on: + create-bucket: + condition: service_completed_successfully + rest: + condition: service_started + environment: + AWS_ACCESS_KEY_ID: ${RUSTFS_ACCESS_KEY} + AWS_SECRET_ACCESS_KEY: ${RUSTFS_SECRET_KEY} + AWS_REGION: us-east-1 + volumes: + - ./spark-defaults.conf:/opt/spark/conf/spark-defaults.conf:ro + ports: + - "8888:8888" + - "8080:8080" + networks: + - iceberg + +networks: + iceberg: + +volumes: + rustfs-data: +``` + +[`rc` 镜像](https://github.com/rustfs/cli)提供官方 RustFS 命令行客户端。初始化程序会在创建 `my-bucket` 前检查其是否存在,因此重复启动不会删除现有仓库数据。RustFS 卷会在容器重新创建后继续保留仓库对象。 + +:::warning[镜像版本] + +Apache Iceberg 快速入门镜像在上游示例中发布时没有稳定版本标签。在将此模式用于本地测试之外的场景前,请将每个镜像固定到经过测试的标签或摘要,并同时验证 Spark、Iceberg runtime 和 REST catalog 的版本。 + +::: + +## 2. 验证并启动部署 + +启动容器前解析 Compose 文件: + +```bash +docker compose config +``` + +启动服务并等待存储桶初始化程序完成: + +```bash +docker compose up -d +docker compose ps -a +``` + +`create-bucket` 服务应显示退出代码 `0`。如果该服务未完成,请检查其日志: + +```bash +docker compose logs create-bucket +``` + +在 `http://localhost:9001` 打开 RustFS 控制台。REST catalog 位于 `http://localhost:8181`,Spark notebook 服务器位于 `http://localhost:8888`。 + +## 3. 创建并查询 Iceberg 表 + +启动 Spark SQL: + +```bash +docker compose exec spark-iceberg spark-sql +``` + +创建命名空间和分区表: + +```sql +CREATE NAMESPACE IF NOT EXISTS demo.nyc; + +CREATE TABLE demo.nyc.taxis +( + vendor_id bigint, + trip_id bigint, + trip_distance float, + fare_amount double, + store_and_fwd_flag string +) +PARTITIONED BY (vendor_id); +``` + +插入并查询示例数据行: + +```sql +INSERT INTO demo.nyc.taxis +VALUES + (1, 1000371, 1.8, 15.32, 'N'), + (2, 1000372, 2.5, 22.15, 'N'), + (2, 1000373, 0.9, 9.01, 'N'), + (1, 1000374, 8.4, 42.13, 'Y'); + +SELECT * FROM demo.nyc.taxis ORDER BY trip_id; +``` + +查询应返回四行: + +```text +1 1000371 1.8 15.32 N +2 1000372 2.5 22.15 N +2 1000373 0.9 9.01 N +1 1000374 8.4 42.13 Y +``` + +## 4. 验证 RustFS 中的对象 + +使用存储桶初始化程序镜像列出仓库内容: + +```bash +docker compose run --rm --entrypoint /bin/sh create-bucket -c \ + '/usr/bin/rc alias set rustfs http://rustfs:9000 "$RUSTFS_ACCESS_KEY" "$RUSTFS_SECRET_KEY" >/dev/null && /usr/bin/rc find rustfs/my-bucket/warehouse' +``` + +输出应包含 `warehouse/nyc/taxis` 前缀下的 Iceberg 元数据和数据对象。你也可以在 RustFS 控制台中检查 `my-bucket` 存储桶。 + +## 5. 停止或重置服务栈 + +停止容器但保留 RustFS 数据卷: + +```bash +docker compose down +``` + +要删除本地仓库并从空的 RustFS 卷重新开始,请显式添加 `--volumes`: + +```bash +docker compose down --volumes +``` + +## 故障排除 + +### Spark 无法连接 RustFS + +在 Compose 内部使用 `http://rustfs:9000`。在 `spark-defaults.conf` 中使用 `http://localhost:9000` 时,它指向的是 Spark 容器自身。 + +确认 `spark.sql.catalog.demo.s3.path-style-access` 为 `true`。虚拟主机样式请求需要额外的 RustFS 域名和 DNS 配置。 + +### Catalog 返回 S3 错误 + +检查 `.env` 中的凭证是否与 RustFS 凭证一致,以及 `create-bucket` 服务是否成功完成: + +```bash +docker compose logs create-bucket rest +``` + +REST catalog 属性 `CATALOG_IO__IMPL` 和 `CATALOG_S3_PATH__STYLE__ACCESS` 使用双下划线;fixture 会将它们转换为带点号和连字符的 Iceberg 属性名。 + +## 后续步骤 + +- 在采用其他 Iceberg 操作前,请查看 [S3 兼容性说明](/administration/protocols/s3)。 +- 通过[访问密钥管理](/security-compliance/iam/access-token)创建专用的生产凭证。 +- 按照 [Apache Iceberg Spark 文档](https://iceberg.apache.org/docs/latest/spark-getting-started/)配置现有 Spark 环境。 \ No newline at end of file diff --git a/content/zh/developer/integration/big-data/index.md b/content/zh/developer/integration/big-data/index.md new file mode 100644 index 000000000..68e6949c2 --- /dev/null +++ b/content/zh/developer/integration/big-data/index.md @@ -0,0 +1,13 @@ +--- +title: "大数据" +description: "通过 S3 兼容的对象存储接口将大数据系统连接到 RustFS。" +--- + +将 **RustFS** 用作支持 S3 兼容端点的大数据系统的对象存储层。 + +## 系统 + +- [Iceberg](./iceberg.md) +- [Milvus](./milvus.md) + +将应用程序数据保存在专用存储桶和前缀中,并使用作用域限定为所需存储桶操作的凭证。 \ No newline at end of file diff --git a/content/zh/developer/integration/big-data/meta.json b/content/zh/developer/integration/big-data/meta.json new file mode 100644 index 000000000..21662d96b --- /dev/null +++ b/content/zh/developer/integration/big-data/meta.json @@ -0,0 +1,7 @@ +{ + "title": "大数据", + "pages": [ + "iceberg", + "milvus" + ] +} \ No newline at end of file diff --git a/content/zh/developer/integration/big-data/milvus.md b/content/zh/developer/integration/big-data/milvus.md new file mode 100644 index 000000000..3170a287f --- /dev/null +++ b/content/zh/developer/integration/big-data/milvus.md @@ -0,0 +1,352 @@ +--- +title: "Milvus" +description: "使用 Docker Compose 运行 Milvus,并将 RustFS 用作兼容 S3 的对象存储后端。" +--- + +本指南将运行 **Milvus Standalone**,并将 **RustFS** 用作兼容 S3 的对象存储后端。你将启动 Milvus、etcd、RustFS 和 Attu,插入示例向量,并验证 Milvus 是否将对象持久化到 RustFS。 + +你需要安装带 Compose 插件的 Docker 和 Python 3.9 或更高版本。此部署仅用于本地集成测试,不适用于生产环境。 + +:::note[Milvus 配置名称] + +Milvus 将兼容 S3 的存储设置归入 `minio` 配置键。该名称并不要求使用 MinIO 服务器。在本指南中,`minio.address` 指向 RustFS 服务,Milvus 使用 RustFS 提供的 S3 API。 + +::: + +## 架构 + +```mermaid +flowchart LR + Client["Milvus client"] -->|gRPC :19530| Milvus["Milvus Standalone"] + Attu["Attu"] -->|gRPC :19530| Milvus + Milvus -->|Metadata| Etcd["etcd"] + Milvus -->|S3 API| RustFS["RustFS"] + Init["Bucket initializer"] -->|Create my-bucket| RustFS +``` + +Milvus 将服务元数据存储在 etcd 中,并将向量数据、索引和相关对象持久化到 RustFS 的 `s3://my-bucket/milvus` 下。运行时数据和缓存仍需要本地 Milvus 卷。 + +## 1. 创建项目文件 + +创建工作目录: + +```bash +mkdir rustfs-milvus +cd rustfs-milvus +``` + +创建环境文件并替换两个凭证占位符: + +```ini title=".env" +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +``` + +请为 Milvus 存储桶使用专用凭证。不要将 `.env` 提交到源代码管理系统。 + +创建 Milvus 存储覆盖配置: + +```yaml title="user.yaml" +common: + storageType: remote + +minio: + address: rustfs:9000 + port: 9000 + bucketName: my-bucket + rootPath: milvus + useSSL: false + useIAM: false + cloudProvider: aws + region: us-east-1 + useVirtualHost: false +``` + +`useVirtualHost: false` 会选择路径样式 S3 请求。主机名 `rustfs` 可在 Compose 网络内部解析;主机上的客户端使用 `http://localhost:9000`。 + +创建 Compose 文件: + +```yaml title="compose.yaml" +services: + etcd: + image: quay.io/coreos/etcd:v3.5.18 + environment: + ETCD_AUTO_COMPACTION_MODE: revision + ETCD_AUTO_COMPACTION_RETENTION: "1000" + ETCD_QUOTA_BACKEND_BYTES: "4294967296" + ETCD_SNAPSHOT_COUNT: "50000" + command: + - etcd + - --advertise-client-urls=http://etcd:2379 + - --listen-client-urls=http://0.0.0.0:2379 + - --data-dir=/etcd + volumes: + - etcd-data:/etcd + healthcheck: + test: ["CMD", "etcdctl", "endpoint", "health"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - milvus + + rustfs: + image: rustfs/rustfs:1.0.0-alpha.83 + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + RUSTFS_VOLUMES: /data + RUSTFS_ADDRESS: 0.0.0.0:9000 + RUSTFS_CONSOLE_ADDRESS: 0.0.0.0:9001 + RUSTFS_CONSOLE_ENABLE: "true" + volumes: + - rustfs-data:/data + ports: + - "9000:9000" + - "9001:9001" + healthcheck: + test: ["CMD-SHELL", "curl -fsS http://localhost:9000/health/ready"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 20s + networks: + - milvus + + create-bucket: + image: rustfs/rc:latest + depends_on: + rustfs: + condition: service_healthy + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + entrypoint: + - /bin/sh + - -c + - | + /usr/bin/rc alias set rustfs http://rustfs:9000 "$${RUSTFS_ACCESS_KEY}" "$${RUSTFS_SECRET_KEY}" \ + --region us-east-1 --bucket-lookup path + /usr/bin/rc bucket create rustfs/my-bucket --ignore-existing + networks: + - milvus + + standalone: + image: milvusdb/milvus:v2.6.0 + command: ["milvus", "run", "standalone"] + security_opt: + - seccomp:unconfined + depends_on: + etcd: + condition: service_healthy + create-bucket: + condition: service_completed_successfully + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: rustfs:9000 + MINIO_ACCESS_KEY_ID: ${RUSTFS_ACCESS_KEY} + MINIO_SECRET_ACCESS_KEY: ${RUSTFS_SECRET_KEY} + MINIO_REGION: us-east-1 + MQ_TYPE: woodpecker + volumes: + - milvus-data:/var/lib/milvus + - ./user.yaml:/milvus/configs/user.yaml:ro + ports: + - "19530:19530" + - "9091:9091" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] + interval: 30s + timeout: 20s + retries: 3 + start_period: 90s + networks: + - milvus + + attu: + image: zilliz/attu:v2.6.5 + depends_on: + standalone: + condition: service_healthy + environment: + MILVUS_URL: standalone:19530 + ports: + - "8000:3000" + networks: + - milvus + +networks: + milvus: + +volumes: + etcd-data: + rustfs-data: + milvus-data: +``` + +`create-bucket` 服务使用官方 [`rc`](https://github.com/rustfs/cli) 镜像,并在确保 `my-bucket` 存在后退出。命名卷会在容器重新创建时保留 etcd 元数据、RustFS 对象和 Milvus 本地数据。 + +:::warning[保护本地服务端口] + +为了进行本地测试,Compose 文件会在主机上发布 RustFS API 和控制台、Milvus gRPC 和健康检查端口以及 Attu。不要将这些端口暴露给不受信任的网络。生产部署需要限定权限的凭证、TLS、身份验证、资源规划、备份,以及独立运行的依赖项。 + +::: + +## 2. 验证并启动部署 + +启动容器前解析 Compose 文件: + +```bash +docker compose config +``` + +启动服务: + +```bash +docker compose up -d +docker compose ps -a +``` + +`create-bucket` 服务应以代码 `0` 退出,`etcd`、`rustfs` 和 `standalone` 应进入健康状态。如果服务未达到预期状态,请检查日志: + +```bash +docker compose logs create-bucket rustfs standalone +``` + +打开以下本地界面: + +- RustFS 控制台:`http://localhost:9001` +- Attu:`http://localhost:8000` +- Milvus 健康端点:`http://localhost:9091/healthz` + +Attu 通过 Compose 网络连接到 `standalone:19530`。如果 Attu 要求输入连接地址,请使用该服务名称,而不是 `localhost:19530`。 + +## 3. 插入并查询示例向量 + +创建 Python 虚拟环境,并安装与服务器版本匹配的 Milvus 客户端: + +```bash +python3 -m venv .venv +source .venv/bin/activate +python -m pip install "pymilvus==2.6.0" +``` + +创建测试脚本: + +```python title="verify_milvus.py" +from pymilvus import MilvusClient + +client = MilvusClient(uri="http://localhost:19530") +collection_name = "rustfs_demo" + +if client.has_collection(collection_name=collection_name): + client.drop_collection(collection_name=collection_name) + +client.create_collection( + collection_name=collection_name, + dimension=4, +) + +client.insert( + collection_name=collection_name, + data=[ + {"id": 1, "vector": [0.1, 0.2, 0.3, 0.4]}, + {"id": 2, "vector": [0.2, 0.3, 0.4, 0.5]}, + {"id": 3, "vector": [0.9, 0.8, 0.7, 0.6]}, + ], +) + +client.flush(collection_name=collection_name) +results = client.search( + collection_name=collection_name, + data=[[0.1, 0.2, 0.3, 0.4]], + limit=2, + output_fields=["id"], +) + +print(results) +client.close() +``` + +运行脚本: + +```bash +python verify_milvus.py +``` + +结果应将 ID 为 `1` 的数据行排在第一位。打开 Attu 并确认 `rustfs_demo` collection 包含三个实体。 + +## 4. 验证 RustFS 中的 Milvus 对象 + +使用存储桶初始化程序镜像列出配置的 `milvus` 根路径下的对象: + +```bash +docker compose run --rm --entrypoint /bin/sh create-bucket -c \ + '/usr/bin/rc alias set rustfs http://rustfs:9000 "$RUSTFS_ACCESS_KEY" "$RUSTFS_SECRET_KEY" --region us-east-1 --bucket-lookup path >/dev/null && /usr/bin/rc find rustfs/my-bucket/milvus' +``` + +输出应包含 Milvus 在 `milvus/` 前缀下创建的对象。你也可以在 RustFS 控制台中打开 `my-bucket`。 + +Milvus 可能会在每个预期对象出现前缓冲或压缩数据。插入、刷新和查询成功,再加上 RustFS 对象列表,共同验证了集成路径。 + +## 5. 停止或重置服务栈 + +停止容器但保留所有命名卷: + +```bash +docker compose down +``` + +要删除本地测试数据(包括 Milvus 存储桶内容和 etcd 元数据),请显式移除卷: + +```bash +docker compose down --volumes +``` + +:::warning[重置会删除测试数据] + +`--volumes` 选项会永久删除此 Compose 项目使用的命名卷。请勿针对需要保留的数据运行此命令。 + +::: + +## 故障排除 + +### Milvus 无法连接 RustFS + +在 Compose 内部使用 `rustfs:9000` 作为 S3 端点。Milvus 容器内的 `localhost:9000` 指向该容器自身,而不是 RustFS。 + +确认 `useVirtualHost` 仍为 `false`,并且传递给 Milvus 的凭证值与 RustFS 凭证一致: + +```bash +docker compose logs standalone rustfs +``` + +### 存储桶初始化程序失败 + +检查 RustFS 就绪状态和初始化程序日志: + +```bash +curl -fsS http://localhost:9000/health/ready +docker compose logs create-bucket +``` + +确认 `.env` 包含非空凭证,并且 `docker compose config` 能够解析这两个变量。 + +### Milvus 启动后没有现有数据 + +对于现有部署,请勿更改 `minio.bucketName`、`minio.rootPath` 或 etcd 根路径。确认 `rustfs-data`、`etcd-data` 和 `milvus-data` 卷仍然存在,并且使用的是同一个 Compose 项目名称。 + +### Attu 无法连接 + +Attu 容器必须使用 `standalone:19530`。浏览器或主机端客户端应使用 `localhost:19530`。检查 Milvus 健康状态和 Attu 日志: + +```bash +curl -fsS http://localhost:9091/healthz +docker compose logs attu standalone +``` + +## 后续步骤 + +- 在启用其他 Milvus 存储功能前,请查看 [S3 兼容性说明](/administration/protocols/s3)。 +- 通过[访问密钥管理](/security-compliance/iam/access-token)创建专用的生产凭证。 +- 将此本地模式调整为托管或分布式部署时,请遵循 [Milvus 文档](https://milvus.io/docs)。 \ No newline at end of file diff --git a/content/zh/developer/integration/index.md b/content/zh/developer/integration/index.md new file mode 100644 index 000000000..ccb6b1b5d --- /dev/null +++ b/content/zh/developer/integration/index.md @@ -0,0 +1,13 @@ +--- +title: "集成" +description: "将 RustFS 与反向代理和大数据系统集成。" +--- + +通过 S3 兼容 API 将 **RustFS** 连接到基础设施和应用平台。 + +## 集成类别 + +- [反向代理](./reverse-proxy/index.md)涵盖 Nginx、Traefik、Caddy 和 HAProxy。 +- [大数据](./big-data/index.md)涵盖 Iceberg。 + +每篇指南都会说明配置集成系统时需要使用的 RustFS 端点和寻址要求。 \ No newline at end of file diff --git a/content/zh/developer/integration/meta.json b/content/zh/developer/integration/meta.json new file mode 100644 index 000000000..7fd420618 --- /dev/null +++ b/content/zh/developer/integration/meta.json @@ -0,0 +1,7 @@ +{ + "title": "集成", + "pages": [ + "reverse-proxy", + "big-data" + ] +} \ No newline at end of file diff --git a/content/zh/developer/integration/reverse-proxy/caddy.md b/content/zh/developer/integration/reverse-proxy/caddy.md new file mode 100644 index 000000000..e2d3241bb --- /dev/null +++ b/content/zh/developer/integration/reverse-proxy/caddy.md @@ -0,0 +1,207 @@ +--- +title: "Caddy" +description: "在 Caddy 后方部署 RustFS,并为独立的 S3 API 和控制台主机名启用自动 HTTPS。" +--- + +使用 **Caddy** 自动获取和续订 TLS 证书,并将不同的主机名分别路由到 RustFS S3 API 和控制台。此部署使用 Docker Compose 运行 Caddy 和单节点 RustFS 实例。你需要 Docker Engine、Docker Compose、一台公网服务器,以及两条解析到该服务器的 DNS 记录。 + +本指南使用以下示例主机名: + +- S3 API 使用 `s3.example.com` +- 控制台使用 `console.example.com` + +请将它们替换为你的公网主机名。Caddy 默认的 ACME 质询要求端口 `80` 和 `443` 可从外部访问。 + +:::warning[从根路径提供 S3 服务] + +不要在 `/s3/` 等路径下发布 S3 API。AWS Signature Version 4 会将请求路径和主机纳入签名,因此重写任一值都可能导致签名请求失效。 + +::: + +## 1. 创建部署目录 + +为部署创建目录: + +```bash +mkdir rustfs-caddy +cd rustfs-caddy +``` + +## 2. 设置部署变量 + +创建环境文件并替换每个值: + +```ini title=".env" +S3_HOSTNAME=s3.example.com +CONSOLE_HOSTNAME=console.example.com +ACME_EMAIL=admin@example.com +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +``` + +请使用能够接收证书通知的电子邮件地址。不要将 `.env` 提交到源代码管理系统。 + +## 3. 配置 Caddy + +创建一个 Caddyfile,为每个 RustFS 端点配置一个站点块: + +```text title="Caddyfile" +{ + email {$ACME_EMAIL} +} + +{$S3_HOSTNAME} { + reverse_proxy rustfs:9000 { + health_uri /health/ready + health_interval 10s + health_timeout 5s + health_fails 3 + health_passes 2 + lb_try_duration 5s + } +} + +{$CONSOLE_HOSTNAME} { + reverse_proxy rustfs:9001 { + health_uri /rustfs/console/health + health_interval 10s + health_timeout 5s + health_fails 3 + health_passes 2 + lb_try_duration 5s + } +} +``` + +Caddy 默认会保留传入的 `Host` 标头、HTTP 方法和请求 URI。它还会通过 `X-Forwarded-*` 标头转发客户端信息,并且无需额外的标头规则即可处理控制台 WebSocket 升级。 + +## 4. 创建 Compose 文件 + +创建 Caddy 和 RustFS 服务: + +```yaml title="compose.yaml" +services: + caddy: + image: caddy:2.10-alpine + restart: unless-stopped + depends_on: + rustfs: + condition: service_healthy + environment: + S3_HOSTNAME: ${S3_HOSTNAME} + CONSOLE_HOSTNAME: ${CONSOLE_HOSTNAME} + ACME_EMAIL: ${ACME_EMAIL} + ports: + - "80:80" + - "443:443" + - "443:443/udp" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-data:/data + - caddy-config:/config + networks: + - rustfs + + rustfs: + image: rustfs/rustfs:latest + restart: unless-stopped + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + RUSTFS_CONSOLE_ENABLE: "true" + RUSTFS_ADDRESS: "0.0.0.0:9000" + RUSTFS_CONSOLE_ADDRESS: "0.0.0.0:9001" + expose: + - "9000" + - "9001" + volumes: + - rustfs-data:/data + healthcheck: + test: ["CMD-SHELL", "curl --fail http://127.0.0.1:9000/health/ready && curl --fail http://127.0.0.1:9001/rustfs/console/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + networks: + - rustfs + +volumes: + caddy-data: + caddy-config: + rustfs-data: + +networks: + rustfs: +``` + +持久化的 `caddy-data` 卷用于存储证书、私钥和 ACME 账户状态。请备份此卷,并且不要共享其中的内容。只有 Caddy 会发布主机端口;RustFS 仅可在 Compose 网络内部访问。 + +## 5. 验证并启动部署 + +渲染 Compose 配置并启动 RustFS: + +```bash +docker compose config +docker compose up -d rustfs +``` + +使用与部署相同的镜像验证 Caddyfile: + +```bash +docker compose run --rm --no-deps caddy caddy validate --config /etc/caddy/Caddyfile +``` + +启动 Caddy 并检查两个服务: + +```bash +docker compose up -d caddy +docker compose ps +docker compose logs --follow caddy +``` + +Caddy 会在后台获取证书,并将 HTTP 请求重定向到 HTTPS。如果签发失败,请确认两条 DNS 记录均解析到此主机、端口 `80` 和 `443` 可以访问,并且 `caddy-data` 卷可写。 + +## 6. 验证两个端点 + +通过各自的公网 HTTPS 主机名验证 API 和控制台: + +```bash +curl --fail https://s3.example.com/health/ready +curl --fail https://console.example.com/rustfs/console/health +``` + +将 S3 客户端端点配置为 `https://s3.example.com`,并启用路径样式寻址。打开 `https://console.example.com` 登录控制台。 + +## 多节点上游 + +对于分布式 RustFS 部署,请在对应的站点块中列出每个节点: + +```text title="Caddyfile" +{$S3_HOSTNAME} { + reverse_proxy node1.example.net:9000 node2.example.net:9000 node3.example.net:9000 node4.example.net:9000 { + lb_policy least_conn + health_uri /health/ready + health_interval 10s + health_timeout 5s + lb_try_duration 5s + } +} + +{$CONSOLE_HOSTNAME} { + reverse_proxy node1.example.net:9001 node2.example.net:9001 node3.example.net:9001 node4.example.net:9001 { + lb_policy cookie rustfs_console + health_uri /rustfs/console/health + health_interval 10s + health_timeout 5s + lb_try_duration 5s + } +} +``` + +将 `` 替换为由所有 Caddy 实例共享的随机密钥。控制台会话亲和性可确保正在进行的 OpenID Connect 登录始终由创建其 `state` 的 RustFS 节点处理。请保持 RustFS 节点之间的端口 `9000` 直接开放,因为内部节点 RPC 使用同一监听器。 + +## 后续步骤 + +- [配置 S3 客户端](/developer/examples/aws-cli) +- [启用虚拟主机样式的存储桶 URL](/integration/virtual) +- [查看健康和就绪端点](/operations/status-check) \ No newline at end of file diff --git a/content/zh/developer/integration/reverse-proxy/haproxy.md b/content/zh/developer/integration/reverse-proxy/haproxy.md new file mode 100644 index 000000000..2ec3e1c10 --- /dev/null +++ b/content/zh/developer/integration/reverse-proxy/haproxy.md @@ -0,0 +1,234 @@ +--- +title: "HAProxy" +description: "在 HAProxy 后方部署 RustFS,为 S3 API 和控制台配置独立的 HTTPS 路由。" +--- + +使用 **HAProxy** 终止 TLS,并将不同的主机名分别路由到 RustFS S3 API 和控制台。此部署使用 Docker Compose 运行 HAProxy 和单节点 RustFS 实例。你需要 Docker Engine、Docker Compose、两条 DNS 记录,以及一张涵盖两个主机名的 TLS 证书。 + +本指南使用以下示例主机名: + +- S3 API 使用 `s3.example.com` +- 控制台使用 `console.example.com` + +请将它们替换为解析到 Docker 主机的主机名。 + +:::warning[从根路径提供 S3 服务] + +不要在 `/s3/` 等路径下发布 S3 API。AWS Signature Version 4 会将请求路径和主机纳入签名,因此重写任一值都可能导致签名请求失效。 + +::: + +## 1. 创建部署目录 + +为 HAProxy 配置和 TLS 证书创建目录: + +```bash +mkdir -p rustfs-haproxy/config rustfs-haproxy/certs +cd rustfs-haproxy +``` + +HAProxy 要求证书链和私钥位于同一个 PEM 文件中。请按以下顺序合并: + +```bash +cat fullchain.pem privkey.pem > certs/rustfs.pem +chmod 600 certs/rustfs.pem +``` + +证书必须涵盖两个公网主机名。 + +## 2. 设置 RustFS 凭证 + +创建环境文件并替换两个凭证占位符: + +```ini title=".env" +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +``` + +不要将此文件或证书私钥提交到源代码管理系统。 + +## 3. 配置 HAProxy + +创建 HAProxy 配置: + +```text title="config/haproxy.cfg" +global + log stdout format raw local0 + +defaults + log global + mode http + option httplog + timeout connect 10s + timeout client 1h + timeout server 1h + timeout http-request 30s + timeout tunnel 1h + +frontend http + bind :80 + http-request redirect scheme https code 301 + +frontend https + bind :443 ssl crt /usr/local/etc/haproxy/certs/rustfs.pem alpn h2,http/1.1 + + acl host_s3 hdr(host) -i s3.example.com + acl host_console hdr(host) -i console.example.com + + use_backend rustfs_s3 if host_s3 + use_backend rustfs_console if host_console + default_backend reject_unknown_host + +backend reject_unknown_host + http-request deny deny_status 404 + +backend rustfs_s3 + balance leastconn + option httpchk GET /health/ready + http-check expect status 200 + server rustfs rustfs:9000 check inter 10s fall 3 rise 2 + +backend rustfs_console + balance leastconn + cookie RUSTFS_CONSOLE insert indirect nocache secure httponly + option httpchk GET /rustfs/console/health + http-check expect status 200 + server rustfs rustfs:9001 check inter 10s fall 3 rise 2 cookie rustfs +``` + +除非显式重写,否则 HAProxy 会保留传入的主机和请求路径。较长的客户端、服务器和隧道超时时间可以满足流式 S3 操作和控制台 WebSocket 连接的需要。 + +控制台后端会设置亲和性 Cookie。只有一台 RustFS 服务器时,它不会影响路由,但保留在基础配置中可以使添加节点后的行为保持一致。 + +## 4. 创建 Compose 文件 + +创建 HAProxy 和 RustFS 服务: + +```yaml title="compose.yaml" +services: + haproxy: + image: haproxy:3.2-alpine + restart: unless-stopped + depends_on: + rustfs: + condition: service_healthy + ports: + - "80:80" + - "443:443" + volumes: + - ./config/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro + - ./certs:/usr/local/etc/haproxy/certs:ro + networks: + - rustfs + + rustfs: + image: rustfs/rustfs:latest + restart: unless-stopped + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + RUSTFS_CONSOLE_ENABLE: "true" + RUSTFS_ADDRESS: "0.0.0.0:9000" + RUSTFS_CONSOLE_ADDRESS: "0.0.0.0:9001" + expose: + - "9000" + - "9001" + volumes: + - rustfs-data:/data + healthcheck: + test: ["CMD-SHELL", "curl --fail http://127.0.0.1:9000/health/ready && curl --fail http://127.0.0.1:9001/rustfs/console/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + networks: + - rustfs + +volumes: + rustfs-data: + +networks: + rustfs: +``` + +只有 HAProxy 会发布主机端口。RustFS 端口 `9000` 和 `9001` 仅可在 Compose 网络内部访问。 + +## 5. 验证并启动部署 + +渲染 Compose 配置并启动 RustFS: + +```bash +docker compose config +docker compose up -d rustfs +``` + +使用与部署相同的镜像验证 HAProxy 配置: + +```bash +docker compose run --rm --no-deps haproxy haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg +``` + +启动 HAProxy 并检查两个服务: + +```bash +docker compose up -d haproxy +docker compose ps +``` + +如果服务未进入健康状态,请检查其日志: + +```bash +docker compose logs haproxy +docker compose logs rustfs +``` + +## 6. 验证两个端点 + +通过各自的公网 HTTPS 主机名验证 API 和控制台: + +```bash +curl --fail https://s3.example.com/health/ready +curl --fail https://console.example.com/rustfs/console/health +``` + +将 S3 客户端端点配置为 `https://s3.example.com`,并启用路径样式寻址。打开 `https://console.example.com` 登录控制台。 + +替换续订后的 `certs/rustfs.pem` 时,请验证配置并重新创建 HAProxy 容器以加载证书: + +```bash +docker compose run --rm --no-deps haproxy haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg +docker compose up -d --force-recreate haproxy +``` + +## 多节点后端 + +对于分布式 RustFS 部署,请将每个 RustFS 节点添加到两个后端: + +```text title="config/haproxy.cfg" +backend rustfs_s3 + balance leastconn + option httpchk GET /health/ready + http-check expect status 200 + server node1 node1.example.net:9000 check inter 10s fall 3 rise 2 + server node2 node2.example.net:9000 check inter 10s fall 3 rise 2 + server node3 node3.example.net:9000 check inter 10s fall 3 rise 2 + server node4 node4.example.net:9000 check inter 10s fall 3 rise 2 + +backend rustfs_console + balance leastconn + cookie RUSTFS_CONSOLE insert indirect nocache secure httponly + option httpchk GET /rustfs/console/health + http-check expect status 200 + server node1 node1.example.net:9001 check inter 10s fall 3 rise 2 cookie node1 + server node2 node2.example.net:9001 check inter 10s fall 3 rise 2 cookie node2 + server node3 node3.example.net:9001 check inter 10s fall 3 rise 2 cookie node3 + server node4 node4.example.net:9001 check inter 10s fall 3 rise 2 cookie node4 +``` + +控制台 Cookie 可确保正在进行的 OpenID Connect 登录始终由创建其 `state` 的 RustFS 节点处理。请保持 RustFS 节点之间的端口 `9000` 直接开放,因为内部节点 RPC 使用同一监听器。 + +## 后续步骤 + +- [配置 S3 客户端](/developer/examples/aws-cli) +- [启用虚拟主机样式的存储桶 URL](/integration/virtual) +- [查看健康和就绪端点](/operations/status-check) \ No newline at end of file diff --git a/content/zh/developer/integration/reverse-proxy/index.md b/content/zh/developer/integration/reverse-proxy/index.md new file mode 100644 index 000000000..721eddc14 --- /dev/null +++ b/content/zh/developer/integration/reverse-proxy/index.md @@ -0,0 +1,19 @@ +--- +title: "反向代理" +description: "为 RustFS S3 API 和控制台选择并配置反向代理。" +--- + +使用反向代理,通过托管主机名和 TLS 端点公开 **RustFS** S3 API 和控制台。 + +建议分别为端口 `9000` 上的 S3 API 和端口 `9001` 上的控制台使用不同的主机名。请从相应主机名的根路径提供 S3 API,因为 S3 客户端会对请求路径进行签名。 + +## 支持的指南 + +- [Nginx](./nginx.md) +- [Traefik](./traefik.md) +- [Caddy](./caddy.md) +- [HAProxy](./haproxy.md) + +## 相关配置 + +当客户端通过虚拟主机样式 URL 访问存储桶时,请参阅[虚拟主机访问](/integration/virtual)。 \ No newline at end of file diff --git a/content/zh/developer/integration/reverse-proxy/meta.json b/content/zh/developer/integration/reverse-proxy/meta.json new file mode 100644 index 000000000..f8b3c1ea6 --- /dev/null +++ b/content/zh/developer/integration/reverse-proxy/meta.json @@ -0,0 +1,9 @@ +{ + "title": "反向代理", + "pages": [ + "nginx", + "traefik", + "caddy", + "haproxy" + ] +} \ No newline at end of file diff --git a/content/zh/developer/integration/reverse-proxy/nginx.md b/content/zh/developer/integration/reverse-proxy/nginx.md new file mode 100644 index 000000000..eecc77f2a --- /dev/null +++ b/content/zh/developer/integration/reverse-proxy/nginx.md @@ -0,0 +1,267 @@ +--- +title: "Nginx" +description: "在 Nginx 后方部署 RustFS,为 S3 API 和控制台配置独立的 HTTPS 端点。" +--- + +使用 **Nginx** 终止 TLS,并将不同的主机名分别路由到 RustFS S3 API 和控制台。此部署使用 Docker Compose 运行 Nginx 和单节点 RustFS 实例。你需要 Docker Engine、Docker Compose、两条 DNS 记录,以及一张涵盖两个主机名的 TLS 证书。 + +本指南使用以下示例主机名: + +- S3 API 使用 `s3.example.com` +- 控制台使用 `console.example.com` + +请将它们替换为解析到 Docker 主机的主机名。 + +:::warning[从根路径提供 S3 服务] + +不要在 `/s3/` 等路径下发布 S3 API。AWS Signature Version 4 会将请求路径和主机纳入签名,因此重写任一值都可能导致签名请求失效。 + +::: + +## 1. 创建部署目录 + +为 Nginx 配置和 TLS 证书创建目录: + +```bash +mkdir -p rustfs-nginx/sites rustfs-nginx/certs +cd rustfs-nginx +``` + +将证书链和私钥复制到 `certs/`: + +```text +rustfs-nginx/ +├── certs/ +│ ├── fullchain.pem +│ └── privkey.pem +└── sites/ +``` + +限制对私钥的访问: + +```bash +chmod 600 certs/privkey.pem +``` + +## 2. 设置 RustFS 凭证 + +创建环境文件并替换两个凭证占位符: + +```ini title=".env" +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +``` + +不要将此文件提交到源代码管理系统。 + +## 3. 配置 Nginx + +创建 Nginx 配置: + +```nginx title="sites/rustfs.conf" +map $http_upgrade $connection_upgrade { + default upgrade; + '' ''; +} + +upstream rustfs_s3 { + server rustfs:9000; + keepalive 32; +} + +upstream rustfs_console { + server rustfs:9001; + keepalive 16; +} + +server { + listen 80; + listen [::]:80; + server_name s3.example.com console.example.com; + + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name s3.example.com; + + ssl_certificate /etc/nginx/certs/fullchain.pem; + ssl_certificate_key /etc/nginx/certs/privkey.pem; + + ignore_invalid_headers off; + client_max_body_size 0; + proxy_buffering off; + proxy_request_buffering off; + + location / { + proxy_http_version 1.1; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ''; + proxy_cache_convert_head off; + proxy_connect_timeout 300s; + chunked_transfer_encoding off; + proxy_pass http://rustfs_s3; + } +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name console.example.com; + + ssl_certificate /etc/nginx/certs/fullchain.pem; + ssl_certificate_key /etc/nginx/certs/privkey.pem; + + client_max_body_size 0; + proxy_buffering off; + proxy_request_buffering off; + + location / { + proxy_http_version 1.1; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_connect_timeout 300s; + proxy_pass http://rustfs_console; + } +} +``` + +S3 服务器会保留原始主机和请求路径,禁用请求缓冲以支持流式上传,并且不会转换已签名的 `HEAD` 请求。控制台服务器还会转发 WebSocket 升级标头。 + +## 4. 创建 Compose 文件 + +创建部署定义: + +```yaml title="compose.yaml" +services: + nginx: + image: nginx:1.25-alpine + restart: unless-stopped + depends_on: + rustfs: + condition: service_healthy + ports: + - "80:80" + - "443:443" + volumes: + - ./sites/rustfs.conf:/etc/nginx/conf.d/rustfs.conf:ro + - ./certs:/etc/nginx/certs:ro + networks: + - rustfs + + rustfs: + image: rustfs/rustfs:latest + restart: unless-stopped + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + RUSTFS_CONSOLE_ENABLE: "true" + RUSTFS_ADDRESS: "0.0.0.0:9000" + RUSTFS_CONSOLE_ADDRESS: "0.0.0.0:9001" + expose: + - "9000" + - "9001" + volumes: + - rustfs-data:/data + healthcheck: + test: ["CMD-SHELL", "curl --fail http://127.0.0.1:9000/health/ready && curl --fail http://127.0.0.1:9001/rustfs/console/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + networks: + - rustfs + +volumes: + rustfs-data: + +networks: + rustfs: +``` + +只有 Nginx 会发布主机端口。RustFS 端口 `9000` 和 `9001` 仅可在 Compose 网络内部访问。 + +## 5. 验证并启动部署 + +启动服务前验证两个配置文件: + +```bash +docker compose config +docker compose up -d rustfs +docker compose run --rm --no-deps nginx nginx -t +``` + +启动 Nginx 并检查两个服务: + +```bash +docker compose up -d nginx +docker compose ps +``` + +如果服务未进入健康状态,请检查其日志: + +```bash +docker compose logs nginx +docker compose logs rustfs +``` + +## 6. 验证两个端点 + +通过各自的公网 HTTPS 主机名验证 API 和控制台: + +```bash +curl --fail https://s3.example.com/health/ready +curl --fail https://console.example.com/rustfs/console/health +``` + +将 S3 客户端端点配置为 `https://s3.example.com`,并启用路径样式寻址。打开 `https://console.example.com` 登录控制台。 + +替换 `certs/` 中续订后的证书或密钥时,请验证配置并重新加载 Nginx,且不会中断活动连接: + +```bash +docker compose exec nginx nginx -t +docker compose exec nginx nginx -s reload +``` + +## 多节点上游 + +对于分布式 RustFS 部署,请将每个上游中的单台服务器替换为所有 RustFS 节点: + +```nginx title="sites/rustfs.conf" +upstream rustfs_s3 { + least_conn; + server node1.example.net:9000; + server node2.example.net:9000; + server node3.example.net:9000; + server node4.example.net:9000; + keepalive 32; +} + +upstream rustfs_console { + ip_hash; + server node1.example.net:9001; + server node2.example.net:9001; + server node3.example.net:9001; + server node4.example.net:9001; + keepalive 16; +} +``` + +控制台上游使用客户端亲和性,因为正在进行的 OpenID Connect 登录会将其 `state` 存储在一个 RustFS 节点上。请保持 RustFS 节点之间的端口 `9000` 开放,因为内部节点 RPC 使用同一监听器。 + +## 后续步骤 + +- [配置 S3 客户端](/developer/examples/aws-cli) +- [启用虚拟主机样式的存储桶 URL](/integration/virtual) +- [查看健康和就绪端点](/operations/status-check) \ No newline at end of file diff --git a/content/zh/developer/integration/reverse-proxy/traefik.md b/content/zh/developer/integration/reverse-proxy/traefik.md new file mode 100644 index 000000000..582a04545 --- /dev/null +++ b/content/zh/developer/integration/reverse-proxy/traefik.md @@ -0,0 +1,241 @@ +--- +title: "Traefik" +description: "在 Traefik 后方部署 RustFS,并为独立的 S3 API 和控制台主机名启用自动 TLS。" +--- + +使用 **Traefik** 及其 Docker 提供程序发现 RustFS、从 Let's Encrypt 获取 TLS 证书,并将不同的主机名分别路由到 S3 API 和控制台。你需要 Docker Engine、Docker Compose、一台公网服务器,以及两条解析到该服务器的 DNS 记录。 + +本指南使用以下示例主机名: + +- S3 API 使用 `s3.example.com` +- 控制台使用 `console.example.com` + +请将它们替换为你的公网主机名。ACME HTTP-01 质询要求端口 `80` 和 `443` 可从外部访问。 + +:::warning[从根路径提供 S3 服务] + +不要在 `/s3/` 等路径下发布 S3 API。AWS Signature Version 4 会将请求路径和主机纳入签名,因此重写任一值都可能导致签名请求失效。 + +::: + +## 1. 创建部署目录 + +创建目录和一个空的 ACME 存储文件。Traefik 要求此文件具有严格的权限: + +```bash +mkdir rustfs-traefik +cd rustfs-traefik +touch acme.json +chmod 600 acme.json +``` + +## 2. 设置部署变量 + +创建环境文件并替换每个值: + +```ini title=".env" +S3_HOSTNAME=s3.example.com +CONSOLE_HOSTNAME=console.example.com +ACME_EMAIL=admin@example.com +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +``` + +请使用能够接收证书到期通知的电子邮件地址。不要将 `.env` 或 `acme.json` 提交到源代码管理系统。 + +## 3. 创建 Compose 文件 + +创建 Traefik 和 RustFS 服务: + +```yaml title="compose.yaml" +services: + traefik: + image: traefik:v3.6.5 + restart: unless-stopped + command: + - --log.level=INFO + - --accesslog=true + - --providers.docker=true + - --providers.docker.endpoint=unix:///var/run/docker.sock + - --providers.docker.exposedbydefault=false + - --providers.docker.network=rustfs + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --entrypoints.web.http.redirections.entrypoint.to=websecure + - --entrypoints.web.http.redirections.entrypoint.scheme=https + - --certificatesresolvers.le.acme.email=${ACME_EMAIL} + - --certificatesresolvers.le.acme.storage=/etc/traefik/acme.json + - --certificatesresolvers.le.acme.httpchallenge=true + - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./acme.json:/etc/traefik/acme.json + networks: + - rustfs + + rustfs: + image: rustfs/rustfs:latest + restart: unless-stopped + environment: + RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} + RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} + RUSTFS_CONSOLE_ENABLE: "true" + RUSTFS_ADDRESS: "0.0.0.0:9000" + RUSTFS_CONSOLE_ADDRESS: "0.0.0.0:9001" + expose: + - "9000" + - "9001" + volumes: + - rustfs-data:/data + healthcheck: + test: ["CMD-SHELL", "curl --fail http://127.0.0.1:9000/health/ready && curl --fail http://127.0.0.1:9001/rustfs/console/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + labels: + - traefik.enable=true + - traefik.docker.network=rustfs + - traefik.http.routers.rustfs-s3.rule=Host(`${S3_HOSTNAME}`) + - traefik.http.routers.rustfs-s3.entrypoints=websecure + - traefik.http.routers.rustfs-s3.tls=true + - traefik.http.routers.rustfs-s3.tls.certresolver=le + - traefik.http.routers.rustfs-s3.service=rustfs-s3 + - traefik.http.services.rustfs-s3.loadbalancer.server.port=9000 + - traefik.http.services.rustfs-s3.loadbalancer.passhostheader=true + - traefik.http.routers.rustfs-console.rule=Host(`${CONSOLE_HOSTNAME}`) + - traefik.http.routers.rustfs-console.entrypoints=websecure + - traefik.http.routers.rustfs-console.tls=true + - traefik.http.routers.rustfs-console.tls.certresolver=le + - traefik.http.routers.rustfs-console.service=rustfs-console + - traefik.http.services.rustfs-console.loadbalancer.server.port=9001 + - traefik.http.services.rustfs-console.loadbalancer.passhostheader=true + networks: + - rustfs + +volumes: + rustfs-data: + +networks: + rustfs: + name: rustfs +``` + +两个路由器使用不同的主机规则和后端端口。RustFS 不会在 Docker 主机上发布端口 `9000` 或 `9001`,Traefik Dashboard 也不会对外公开。 + +:::note[Docker 套接字访问] + +Traefik 通过只读 Docker 套接字挂载读取容器标签。任何能够修改 Docker 工作负载的用户都可以影响 Docker 提供程序发现的路由。请限制对代理主机上 Docker 的访问。 + +::: + +## 4. 验证并启动部署 + +渲染 Compose 配置并检查所有变量是否都已解析: + +```bash +docker compose config +``` + +启动两个服务: + +```bash +docker compose up -d +docker compose ps +``` + +在 Traefik 完成 ACME 质询并创建两张证书期间跟踪其日志: + +```bash +docker compose logs --follow traefik +``` + +如果证书签发失败,请确认两条 DNS 记录均解析到此主机,并且端口 `80` 和 `443` 可从互联网访问。Let's Encrypt 存在速率限制,因此请先修正 DNS 和防火墙问题,再反复重新创建部署。 + +## 5. 验证两个端点 + +通过 Traefik 验证 S3 API 就绪端点和控制台健康端点: + +```bash +curl --fail https://s3.example.com/health/ready +curl --fail https://console.example.com/rustfs/console/health +``` + +将 S3 客户端端点配置为 `https://s3.example.com`,并启用路径样式寻址。打开 `https://console.example.com` 登录控制台。 + +## 多节点服务 + +对于外部多节点 RustFS 集群,请在 `traefik` 服务中启用 Traefik 文件提供程序: + +```yaml title="compose.yaml" +services: + traefik: + command: + - --providers.file.filename=/etc/traefik/dynamic.yaml + - --providers.file.watch=true + volumes: + - ./dynamic.yaml:/etc/traefik/dynamic.yaml:ro +``` + +创建包含每个 RustFS 节点的动态配置: + +```yaml title="dynamic.yaml" +http: + routers: + rustfs-s3: + rule: Host(`s3.example.com`) + entryPoints: + - websecure + service: rustfs-s3 + tls: + certResolver: le + rustfs-console: + rule: Host(`console.example.com`) + entryPoints: + - websecure + service: rustfs-console + tls: + certResolver: le + + services: + rustfs-s3: + loadBalancer: + passHostHeader: true + healthCheck: + path: /health/ready + interval: 10s + timeout: 5s + servers: + - url: http://node1.example.net:9000 + - url: http://node2.example.net:9000 + - url: http://node3.example.net:9000 + - url: http://node4.example.net:9000 + rustfs-console: + loadBalancer: + passHostHeader: true + sticky: + cookie: + name: rustfs_console + secure: true + httpOnly: true + healthCheck: + path: /rustfs/console/health + interval: 10s + timeout: 5s + servers: + - url: http://node1.example.net:9001 + - url: http://node2.example.net:9001 + - url: http://node3.example.net:9001 + - url: http://node4.example.net:9001 +``` + +使用 OpenID Connect 时,请为控制台服务配置粘性会话。正在进行的登录会将其 `state` 存储在一个 RustFS 节点上,回调必须返回该节点。请保持 RustFS 节点之间的端口 `9000` 直接开放,因为内部节点 RPC 使用同一监听器。 + +## 后续步骤 + +- [配置 S3 客户端](/developer/examples/aws-cli) +- [启用虚拟主机样式的存储桶 URL](/integration/virtual) +- [查看健康和就绪端点](/operations/status-check) \ No newline at end of file diff --git a/content/zh/developer/license.md b/content/zh/developer/license.md new file mode 100644 index 000000000..c62c0ee5c --- /dev/null +++ b/content/zh/developer/license.md @@ -0,0 +1,97 @@ +--- +title: RustFS 开源许可证 +description: RustFS 根据 Apache 2.0 许可证发布。 +--- + +## 开源许可证 + +- RustFS 根据 Apache 2.0 许可证发布。 +- [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) + +## 许可条款 + +_版本 2.0,2004 年 1 月_ +http://www.apache.org/licenses/ + +### 使用、复制和分发的条款与条件 + +#### 定义 + +“许可证”是指本文件第 1 至第 9 节所定义的使用、复制和分发条款与条件。 + +“许可方”是指授予本许可证的版权所有者,或经版权所有者授权的实体。 + +“法律实体”是指行为实体与控制该实体、受该实体控制或与该实体共同受控的所有其他实体的联合体。就本定义而言,“控制”是指:**(i)** 无论通过合同还是其他方式,直接或间接决定该实体方向或管理的权力;**(ii)** 拥有百分之五十(50%)或以上的已发行股份;或 **(iii)** 对该实体的实益所有权。 + +“您”(或“您的”)是指行使本许可证所授予权限的个人或法律实体。 + +“源代码”形式是指进行修改时首选的形式,包括但不限于软件源代码、文档源文件和配置文件。 + +“目标代码”形式是指对源代码形式进行机械转换或翻译后产生的任何形式,包括但不限于编译后的目标代码、生成的文档以及向其他媒体类型的转换结果。 + +“作品”是指以源代码或目标代码形式存在,并根据本许可证提供的著作权作品;作品中包含或附有版权声明(示例见下文附录)。 + +“衍生作品”是指以源代码或目标代码形式存在、基于(或衍生自)本作品,并且其编辑修订、注释、扩充或其他修改作为整体构成原创著作权作品的任何作品。就本许可证而言,衍生作品不包括仍可与本作品及其衍生作品的接口分离,或仅通过名称链接(或绑定)到这些接口的作品。 + +“贡献”是指由版权所有者或经授权代表版权所有者提交的个人或法律实体,有意提交给许可方以纳入本作品的任何著作权作品,包括本作品的原始版本以及对本作品或其衍生作品的任何修改或补充。就本定义而言,“提交”是指发送给许可方或其代表的任何形式的电子、口头或书面通信,包括但不限于在由许可方或代表许可方管理、旨在讨论和改进本作品的电子邮件列表、源代码控制系统和问题跟踪系统中的通信,但版权所有者以书面形式明确标注或以其他方式指定为“非贡献”的通信除外。 + +“贡献者”是指许可方,以及许可方已代表其接收贡献并随后将该贡献纳入本作品的任何个人或法律实体。 + +#### 授予版权许可 + +根据本许可证的条款与条件,每位贡献者特此向您授予永久的、全球范围的、非独占的、免费的、免版税的、不可撤销的版权许可,允许您以源代码或目标代码形式复制本作品、创作本作品的衍生作品、公开展示、公开表演、再许可和分发本作品及此类衍生作品。 + +#### 授予专利许可 + +根据本许可证的条款与条件,每位贡献者特此向您授予永久的、全球范围的、非独占的、免费的、免版税的、不可撤销的(本节另有规定的除外)专利许可,允许您制造、委托制造、使用、许诺销售、销售、进口以及以其他方式转让本作品;该许可仅适用于该贡献者有权许可,且仅因其贡献本身或其贡献与提交该贡献所对应的本作品相结合而必然受到侵犯的专利权利要求。如果您对任何实体提起专利诉讼(包括诉讼中的交叉诉讼或反诉),声称本作品或纳入本作品的贡献构成直接或帮助专利侵权,则根据本许可证就该作品授予您的任何专利许可自提起该诉讼之日起终止。 + +#### 再分发 + +您可以在任何媒介中,以修改或未修改的形式,以及源代码或目标代码形式复制和分发本作品或其衍生作品,但须满足以下条件: + +* **(a)** 您必须向本作品或衍生作品的任何其他接收者提供本许可证的副本;并且 +* **(b)** 您必须使任何修改过的文件带有醒目的声明,说明您已更改这些文件;并且 +* **(c)** 您必须在所分发的任何衍生作品的源代码形式中,保留本作品源代码形式中的所有版权、专利、商标和署名声明,但与衍生作品任何部分无关的声明除外;并且 +* **(d)** 如果本作品在分发时包含名为“NOTICE”的文本文件,则您分发的任何衍生作品都必须包含该 NOTICE 文件中署名声明的可读副本,但与衍生作品任何部分无关的声明除外;副本应至少置于以下位置之一:作为衍生作品一部分分发的 NOTICE 文本文件中;随衍生作品提供的源代码形式或文档中;或者,在衍生作品生成的显示内容中(如果且仅在此类第三方声明通常出现的位置)。NOTICE 文件的内容仅供参考,不会修改本许可证。您可以在所分发的衍生作品中,在本作品 NOTICE 文本旁边或作为其附录添加您自己的署名声明,但此类附加署名声明不得被解释为修改本许可证。 + +您可以为自己的修改添加版权声明,也可以为您的修改或任何此类衍生作品整体的使用、复制或分发提供附加或不同的许可条款与条件,前提是您对本作品的使用、复制和分发在其他方面遵守本许可证规定的条件。 + +#### 提交贡献 + +除非您明确另有说明,否则您有意提交给许可方以纳入本作品的任何贡献,均应遵循本许可证的条款与条件,且不附加任何条款或条件。尽管有上述规定,本条款中的任何内容均不得取代或修改您可能已与许可方签署的、涉及此类贡献的任何单独许可协议的条款。 + +#### 商标 + +除非是在描述本作品来源和复制 NOTICE 文件内容时进行合理且惯常的使用,否则本许可证不授予使用许可方商号、商标、服务标志或产品名称的权限。 + +#### 免责声明 + +除非适用法律要求或书面约定,许可方按“原样”提供本作品(每位贡献者也按“原样”提供其贡献),不附带任何明示或默示的担保或条件,包括但不限于对所有权、不侵权、适销性或特定用途适用性的任何担保或条件。您应自行负责判断使用或再分发本作品是否适当,并承担因行使本许可证所授予权限而产生的任何风险。 + +#### 责任限制 + +在任何情况下和任何法律理论下,无论是侵权行为(包括过失)、合同还是其他理论,除非适用法律要求(例如故意和重大过失行为)或书面约定,任何贡献者均不对您承担损害赔偿责任,包括因本许可证或使用、无法使用本作品而产生的任何性质的直接、间接、特殊、偶发或后果性损害(包括但不限于商誉损失、停工、计算机故障或失灵,以及任何和所有其他商业损害或损失),即使该贡献者已被告知可能发生此类损害。 + +#### 接受担保或附加责任 + +在再分发本作品或其衍生作品时,您可以选择提供与本许可证一致的支持、担保、赔偿或其他责任义务和/或权利,并就此收费。但是,在接受此类义务时,您只能代表自己并自行承担责任,而不能代表任何其他贡献者;并且只有在您同意赔偿、为每位贡献者抗辩并使其免受因您接受任何此类担保或附加责任而产生的任何责任或对其提出的索赔时,方可这样做。 + +_条款与条件结束_ + +### 附录:如何将 Apache 许可证应用于您的作品 + +要将 Apache 许可证应用于您的作品,请附上以下标准声明,并将方括号 `[]` 中的字段替换为您自己的身份信息。(不要包含方括号!)该文本应包含在适合相应文件格式的注释语法中。我们还建议在与版权声明相同的“打印页面”中包含文件名或类名以及用途说明,以便在第三方归档中更容易识别。 + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/content/zh/developer/mcp.md b/content/zh/developer/mcp.md new file mode 100644 index 000000000..4ddbe6261 --- /dev/null +++ b/content/zh/developer/mcp.md @@ -0,0 +1,269 @@ +--- +title: "RustFS MCP" +description: "RustFS MCP 使用指南。" +--- + +**RustFS MCP Server** 是一个高性能 [Model Context Protocol (MCP)](https://www.anthropic.com/news/model-context-protocol) 服务器,可让 AI/LLM 工具无缝访问兼容 S3 的对象存储操作。它使用 Rust 构建以实现高性能和安全性,使 Claude Desktop 等 AI 助手能够通过标准化协议与云存储交互。 + +### 什么是 MCP? + +Model Context Protocol 是一项开放标准,使 AI 应用程序能够与外部系统建立安全、可控的连接。此服务器充当 AI 工具与兼容 S3 的存储服务之间的桥梁,在保持安全性和可观测性的同时,提供对文件操作的结构化访问。 + +## ✨ 功能 + +### 支持的 S3 操作 + +- **列出存储桶**:列出所有可访问的 S3 存储桶。 +- **列出对象**:浏览存储桶内容,支持可选的前缀筛选。 +- **上传文件**:上传本地文件,并自动检测 MIME 类型和设置缓存控制。 +- **获取对象**:从 S3 存储中获取对象,支持读取或下载模式。 + +## 🔧 安装 + +:::warning[构建说明可能已过时] + +`rustfs-mcp` crate 已不再属于当前 `rustfs/rustfs` 主分支,因此以下构建命令可能无法用于新克隆的仓库。从源代码构建前,请在 [RustFS GitHub 组织](https://github.com/rustfs)中确认 MCP 服务器的当前位置。 + +::: + +### 前置要求 + +- Rust 1.75+(用于从源代码构建) +- 已配置的 AWS 凭证(通过环境变量、AWS CLI 或 IAM 角色) +- 能够访问兼容 S3 的存储服务 + +### 从源代码构建 + +```bash +# Clone the repository +git clone https://github.com/rustfs/rustfs.git +cd rustfs + +# Build the MCP server +cargo build --release -p rustfs-mcp + +# Binary will be available at +./target/release/rustfs-mcp +``` + +## ⚙️ 配置 + +### 环境变量 + +```bash +# AWS credentials (required) +export AWS_ACCESS_KEY_ID=your_access_key +export AWS_SECRET_ACCESS_KEY=your_secret_key +export AWS_REGION=us-east-1 # optional, defaults to us-east-1 + +# Optional: Custom S3 endpoint (for MinIO, etc.) +export AWS_ENDPOINT_URL=http://localhost:9000 + +# Log level (optional) +export RUST_LOG=info +``` + +### 命令行选项 + +```bash +rustfs-mcp --help +``` + +服务器支持多种命令行选项来自定义行为: + +- `--access-key-id`:用于 S3 身份验证的 AWS 访问密钥 ID +- `--secret-access-key`:用于 S3 身份验证的 AWS 私有访问密钥 +- `--region`:S3 操作使用的 AWS 区域(默认值:us-east-1) +- `--endpoint-url`:自定义 S3 端点 URL(用于 MinIO、LocalStack 等) +- `--log-level`:日志级别配置(默认值:rustfs_mcp_server=info) + +## 🚀 使用 + +### 启动服务器 + +```bash +# Start the MCP server +rustfs-mcp + +# Or with custom options +rustfs-mcp --log-level debug --region us-west-2 +``` + +### 与聊天客户端集成 + +#### 选项 1:使用命令行参数 + +```json +{ + "mcpServers": { + "rustfs-mcp": { + "command": "/path/to/rustfs-mcp", + "args": [ + "--access-key-id", "your_access_key", + "--secret-access-key", "your_secret_key", + "--region", "us-west-2", + "--log-level", "info" + ] + } + } +} +``` + +#### 选项 2:使用环境变量 + +```json +{ + "mcpServers": { + "rustfs-mcp": { + "command": "/path/to/rustfs-mcp", + "env": { + "AWS_ACCESS_KEY_ID": "your_access_key", + "AWS_SECRET_ACCESS_KEY": "your_secret_key", + "AWS_REGION": "us-east-1" + } + } + } +} +``` + +### 使用 Docker + +[RustFS MCP 官方提供了 Dockerfile](https://github.com/rustfs/rustfs/tree/main/crates/mcp),可用于构建使用 RustFS MCP 的容器镜像。 + +```bash +# Clone RustFS repository code +git clone https://github.com/rustfs/rustfs.git + +# Build Docker image +docker build -f crates/mcp/Dockerfile -t rustfs/rustfs-mcp . +``` + +构建成功后,你可以在 AI IDE 的 MCP 配置中进行配置。 + +#### 在 AI IDE 中配置 MCP + +目前 Cursor、Windsurf、Trae 等主流 AI IDE 均支持 MCP。例如,在 Trae 中,将以下内容添加到 MCP 配置(**MCP --> Add**): + +```json +{ + "mcpServers": { + "rustfs-mcp": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "-e", + "AWS_ACCESS_KEY_ID", + "-e", + "AWS_SECRET_ACCESS_KEY", + "-e", + "AWS_REGION", + "-e", + "AWS_ENDPOINT_URL", + "rustfs/rustfs-mcp" + ], + "env": { + "AWS_ACCESS_KEY_ID": "rustfs_access_key", + "AWS_SECRET_ACCESS_KEY": "rustfs_secret_key", + "AWS_REGION": "us-east-1", + "AWS_ENDPOINT_URL": "rustfs_instance_url" + } + } + } +} +``` + +> `AWS_ACCESS_KEY_ID` 和 `AWS_SECRET_ACCESS_KEY` 是 RustFS 访问密钥。你可以参考[访问密钥管理章节](../security-compliance/iam/access-token.md)进行创建。 + +添加成功后,你可以在 MCP 配置页面列出[可用工具](#️-available-tools)。 + +![在 Trae MCP 配置中成功添加 RustFS MCP](images/add-rustfs-mcp-succ.png) + +在 Trae 中,你可以通过输入相应的提示词使用对应工具。例如,在 Trae 的聊天对话框中输入: + +```text +Please help me list the buckets in the current rustfs instance, thank you! +``` + +将返回以下响应: + +![使用 RustFS MCP 列出 RustFS 存储桶](images/list-rustfs-bucket-with-mcp.png) + +Trae 使用 **Builder with MCP** 模式,调用 `list_buckets` 工具列出已配置 RustFS 实例中的所有存储桶。调用其他工具时同样如此。 + +## 🛠️ 可用工具 + +MCP 服务器公开以下工具供 AI 助手使用: + +### `list_buckets` + +列出使用已配置凭证可访问的所有 S3 存储桶。 + +**参数**:无 + +### `list_objects` + +列出 S3 存储桶中的对象,支持可选的前缀筛选。 + +**参数**: + +- `bucket_name`(字符串):S3 存储桶名称 +- `prefix`(字符串,可选):用于筛选对象的前缀 + +### `upload_file` + +将本地文件上传到 S3,并自动检测 MIME 类型。 + +**参数**: + +- `local_file_path`(字符串):本地文件路径 +- `bucket_name`(字符串):目标 S3 存储桶 +- `object_key`(字符串):S3 对象键(目标路径) +- `content_type`(字符串,可选):内容类型(未提供时自动检测) +- `storage_class`(字符串,可选):S3 存储类别 +- `cache_control`(字符串,可选):缓存控制标头 + +### `get_object` + +使用两种操作模式从 S3 获取对象:直接读取内容或下载到文件。 + +**参数**: + +- `bucket_name`(字符串):源 S3 存储桶 +- `object_key`(字符串):S3 对象键 +- `version_id`(字符串,可选):版本化对象的版本 ID +- `mode`(字符串,可选):操作模式,"read"(默认)直接返回内容,"download" 保存到本地文件 +- `local_path`(字符串,可选):本地文件路径(当 mode 为 "download" 时必填) +- `max_content_size`(数字,可选):读取模式下的最大内容大小,以字节为单位(默认值:1MB) + +### `create_bucket` + +创建新的 RustFS 存储桶。 + +**参数**: + +- `bucket_name`(字符串):要创建的存储桶名称。 + +### `delete_bucket` + +删除指定的 RustFS 存储桶。 + +**参数**: + +- `bucket_name`(字符串):要删除的存储桶名称。 + +## 架构 + +MCP 服务器采用模块化架构构建: + +```text +rustfs-mcp/ +├── src/ +│ ├── main.rs # Entry point, CLI parsing and server initialization +│ ├── server.rs # MCP server implementation and tool handlers +│ ├── s3_client.rs # S3 client wrapper with async operations +│ ├── config.rs # Configuration management and CLI options +│ └── lib.rs # Library exports and public API +└── Cargo.toml # Dependencies, metadata and binary configuration +``` \ No newline at end of file diff --git a/content/zh/developer/meta.json b/content/zh/developer/meta.json new file mode 100644 index 000000000..f175aa0b2 --- /dev/null +++ b/content/zh/developer/meta.json @@ -0,0 +1,9 @@ +{ + "title": "开发者", + "defaultOpen": false, + "pages": [ + "sdk", + "integration", + "license" + ] +} \ No newline at end of file diff --git a/content/zh/developer/sdk/go.md b/content/zh/developer/sdk/go.md new file mode 100644 index 000000000..359c787f3 --- /dev/null +++ b/content/zh/developer/sdk/go.md @@ -0,0 +1,222 @@ +--- +title: "Golang SDK 指南" +description: "使用 AWS SDK for Go v2 操作 RustFS 实例,包括创建和删除存储桶与对象。" +--- + +RustFS 不提供第一方 Go SDK。RustFS 与 S3 完全兼容,因此你可以配置官方 AWS SDK for Go v2,使其指向 RustFS 服务器。通过该 SDK,你可以操作 RustFS,包括创建和删除存储桶或对象、上传和下载文件等。 + +## 前提条件 + +- Go 1.21 或更高版本 +- 一个正常运行的 RustFS 实例(请参阅[安装指南](../../installation/index.md));S3 API 监听端口 `9000`,控制台监听端口 `9001` +- 安装时通过 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` 环境变量设置的访问密钥(请参阅[访问密钥管理](../../security-compliance/iam/access-token.md)) + +:::tip[本地测试] + +如果安装时未设置凭证,服务器默认使用 `rustfsadmin` / `rustfsadmin`。这仅适合一次性本地试用,切勿用于其他人可访问的环境。 + +::: + +安装 SDK 模块: + +```bash +go mod init rustfs-go-demo +go get github.com/aws/aws-sdk-go-v2/aws +go get github.com/aws/aws-sdk-go-v2/credentials +go get github.com/aws/aws-sdk-go-v2/service/s3 +``` + +## 初始化客户端 + +以下是一个可直接运行的完整程序。它从环境变量读取配置,并通过 `aws.Config` 初始化客户端: + +```go title="main.go" +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +func main() { + region := os.Getenv("RUSTFS_REGION") + accessKeyID := os.Getenv("RUSTFS_ACCESS_KEY_ID") + secretAccessKey := os.Getenv("RUSTFS_SECRET_ACCESS_KEY") + endpoint := os.Getenv("RUSTFS_ENDPOINT_URL") + + if accessKeyID == "" || secretAccessKey == "" || region == "" || endpoint == "" { + log.Fatal("missing the env: RUSTFS_ACCESS_KEY_ID / RUSTFS_SECRET_ACCESS_KEY / RUSTFS_REGION / RUSTFS_ENDPOINT_URL") + } + + // build aws.Config + cfg := aws.Config{ + Region: region, + Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, "")), + } + + // build S3 client + client := s3.NewFromConfig(cfg, func(o *s3.Options) { + o.BaseEndpoint = aws.String(endpoint) + // RustFS uses path-style URLs by default; virtual-host style requires RUSTFS_SERVER_DOMAINS + o.UsePathStyle = true + }) + + ctx := context.Background() + + resp, err := client.ListBuckets(ctx, &s3.ListBucketsInput{}) + if err != nil { + log.Fatalf("list buckets failed: %v", err) + } + + fmt.Println("Buckets:") + for _, b := range resp.Buckets { + fmt.Println(" -", *b.Name) + } +} +``` + +:::note + +这些环境变量名(`RUSTFS_ENDPOINT_URL`、`RUSTFS_REGION`、`RUSTFS_ACCESS_KEY_ID`、`RUSTFS_SECRET_ACCESS_KEY`)只是本示例的客户端约定,由你的 Go 程序读取,而不是由 RustFS 读取。它们不同于安装 RustFS 时使用的服务器端变量 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY`。 + +::: + +运行该程序(如果 RustFS 在另一台计算机上运行,请将 `localhost` 替换为服务器 IP 地址): + +```bash +export RUSTFS_ENDPOINT_URL="http://localhost:9000" +export RUSTFS_REGION="us-east-1" +export RUSTFS_ACCESS_KEY_ID="" +export RUSTFS_SECRET_ACCESS_KEY="" +go run main.go +``` + +```text +Buckets: + - my-bucket +``` + +现在可以执行存储桶和对象操作。以下代码片段在上述 `main` 函数内运行,并复用 `client` 和 `ctx`。 + +## 创建存储桶 + +```go +_, err = client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String("my-bucket"), +}) +if err != nil { + log.Fatalf("create bucket failed: %v", err) +} +fmt.Println("bucket created") +``` + +```text +bucket created +``` + +## 列出存储桶 + +```go +resp, err := client.ListBuckets(ctx, &s3.ListBucketsInput{}) +if err != nil { + log.Fatalf("list buckets failed: %v", err) +} + +fmt.Println("Buckets:") +for _, b := range resp.Buckets { + fmt.Println(" -", *b.Name) +} +``` + +```text +Buckets: + - my-bucket +``` + +## 删除存储桶 + +```go +_, err = client.DeleteBucket(ctx, &s3.DeleteBucketInput{ + Bucket: aws.String("my-bucket"), +}) +if err != nil { + log.Fatalf("delete bucket failed: %v", err) +} +fmt.Println("bucket deleted") +``` + +```text +bucket deleted +``` + +## 列出对象 + +```go +resp, err := client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ + Bucket: aws.String("my-bucket"), +}) +if err != nil { + log.Fatalf("list object failed: %v", err) +} +for _, obj := range resp.Contents { + fmt.Println(" -", *obj.Key) +} +``` + +```text + - hello.txt +``` + +## 上传对象 + +上传字符串正文(在 import 中添加 `"strings"`): + +```go +_, err = client.PutObject(ctx, &s3.PutObjectInput{ + Bucket: aws.String("my-bucket"), + Key: aws.String("hello.txt"), + Body: strings.NewReader("hello rustfs"), +}) +if err != nil { + log.Fatalf("upload object failed: %v", err) +} +fmt.Println("object uploaded") +``` + +```text +object uploaded +``` + +## 下载对象 + +读取对象正文(在 import 中添加 `"io"`): + +```go +resp, err := client.GetObject(ctx, &s3.GetObjectInput{ + Bucket: aws.String("my-bucket"), + Key: aws.String("hello.txt"), +}) +if err != nil { + log.Fatalf("download object fail: %v", err) +} +defer resp.Body.Close() + +// read object content +data, err := io.ReadAll(resp.Body) +if err != nil { + log.Fatalf("read object content fail: %v", err) +} +fmt.Println("content is :", string(data)) +``` + +```text +content is : hello rustfs +``` + +有关其他操作(预签名 URL、分段上传等),请参阅 [AWS SDK for Go v2 文档](https://aws.github.io/aws-sdk-go-v2/docs/)。所有 S3 兼容调用都能以相同方式用于 RustFS。 \ No newline at end of file diff --git a/content/zh/developer/sdk/index.md b/content/zh/developer/sdk/index.md new file mode 100644 index 000000000..da75cc8d3 --- /dev/null +++ b/content/zh/developer/sdk/index.md @@ -0,0 +1,43 @@ +--- +title: "RustFS SDK 概述" +description: "概述 RustFS 支持的 S3 SDK。" +--- + +RustFS 是兼容 S3 协议的分布式对象存储系统。你可以: + +- 通过控制台管理界面管理 RustFS。 +- 通过 S3 客户端管理 RustFS。 +- 通过 SDK 在业务侧实现对象存储操作和管理。 + +目前,RustFS 提供的 SDK 指南包括: + +- [Java SDK](./java.md) +- [JavaScript SDK](./javascript.md) +- [Python SDK](./python.md) +- [Rust SDK](./rust.md) +- [TypeScript SDK](./typescript.md) +- [Golang SDK](./go.md) + +## 术语 + +Amazon S3(Simple Storage Service,简单存储服务)是首个得到广泛采用的对象存储服务,其 API 已成为对象存储的事实标准。在本文档中,“S3”指该协议。 + +## SDK 建议 + +我们建议使用 AWS 官方 S3 SDK。这些 SDK 成熟、维护良好并经过充分优化。 + +如果你熟悉并信任某个供应商的 SDK,也可以使用它。 + +部分第三方 SDK 可能采用非标准实现。我们建议避免使用未严格遵循 S3 标准的 SDK。 + +## 与 MinIO SDK 的兼容性 + +是的,RustFS 与 MinIO SDK 完全兼容。 + +如果你正在使用 MinIO SDK,可以修改 Endpoint、AK 和 SK,以直接兼容 RustFS。 + +## 处理不兼容的 SDK + +如果遇到不支持标准 S3、MinIO 或 RustFS 的 SDK: + +我们建议改用标准 AWS S3 SDK。 \ No newline at end of file diff --git a/content/zh/developer/sdk/java.md b/content/zh/developer/sdk/java.md new file mode 100644 index 000000000..f41103481 --- /dev/null +++ b/content/zh/developer/sdk/java.md @@ -0,0 +1,345 @@ +--- +title: "Java SDK 指南" +description: "将官方 AWS SDK for Java v2 与 RustFS 配合使用。" +--- + +RustFS 不提供第一方 Java SDK。RustFS 与 S3 兼容,因此你可以配置官方 AWS SDK for Java v2,使其指向 RustFS 服务器。 + +## 1. 前提条件 + +* Java 8 或更高版本,以及 Maven(或 Gradle) +* 一个正在运行的 RustFS 实例(请参阅[安装指南](../../installation/index.md));S3 API 监听端口 `9000`,控制台监听端口 `9001` +* 安装时通过 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` 环境变量设置的访问密钥(请参阅[访问密钥管理](../../security-compliance/iam/access-token.md)) + +:::tip[本地测试] + +如果安装时未设置凭证,服务器默认使用 `rustfsadmin` / `rustfsadmin`。这仅适合一次性本地试用,切勿用于其他人可访问的环境。 + +::: + +### 1.1 设置 Maven 项目 + +创建一个新的 Maven 项目: + +```text +rustfs-java-s3-demo/ +├── pom.xml +└── src/ + └── main/ + └── java/ + └── com/ + └── example/ + └── RustfsS3Example.java +``` + +### 1.2 添加依赖项 + +在 `pom.xml` 中添加 AWS SDK 依赖项: + +```xml title="pom.xml" + + + software.amazon.awssdk + s3 + 2.25.27 + + +``` + +> 建议使用 AWS SDK v2。该版本功能更完整,并支持异步、响应式等模式。 + +--- + +## 2. 连接到 RustFS + +### 2.1 完整示例 + +以下类可直接编译和运行。如果 RustFS 在另一台计算机上运行,请将 `localhost` 替换为服务器 IP 地址,并填写你自己的访问密钥: + +```java title="RustfsS3Example.java" +package com.example; + +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.*; + +import java.net.URI; +import java.nio.file.Paths; + +public class RustfsS3Example { + + public static void main(String[] args) { + // 1. Initialize S3 client + S3Client s3 = S3Client.builder() + .endpointOverride(URI.create("http://localhost:9000")) // RustFS S3 API address + .region(Region.US_EAST_1) // RustFS default region + .credentialsProvider( + StaticCredentialsProvider.create( + AwsBasicCredentials.create("", "") + ) + ) + // RustFS uses path-style URLs by default; virtual-host style requires RUSTFS_SERVER_DOMAINS + .forcePathStyle(true) + .build(); + + // 2. Create bucket + String bucket = "my-bucket"; + try { + s3.createBucket(CreateBucketRequest.builder().bucket(bucket).build()); + System.out.println("Bucket created: " + bucket); + } catch (BucketAlreadyExistsException | BucketAlreadyOwnedByYouException e) { + System.out.println("Bucket already exists."); + } + + // 3. Upload file + s3.putObject( + PutObjectRequest.builder().bucket(bucket).key("hello.txt").build(), + Paths.get("/path/to/hello.txt") + ); + System.out.println("Uploaded hello.txt"); + + // 4. Download file + s3.getObject( + GetObjectRequest.builder().bucket(bucket).key("hello.txt").build(), + Paths.get("downloaded-hello.txt") + ); + System.out.println("Downloaded hello.txt"); + + // 5. List objects + ListObjectsV2Response listResponse = s3.listObjectsV2(ListObjectsV2Request.builder().bucket(bucket).build()); + listResponse.contents().forEach(obj -> System.out.println("Found object: " + obj.key())); + + // 6. Delete object + s3.deleteObject(DeleteObjectRequest.builder().bucket(bucket).key("hello.txt").build()); + System.out.println("Deleted hello.txt"); + + // 7. Delete bucket (optional) + // s3.deleteBucket(DeleteBucketRequest.builder().bucket(bucket).build()); + } +} +``` + +预期输出: + +```text +Bucket created: my-bucket +Uploaded hello.txt +Downloaded hello.txt +Found object: hello.txt +Deleted hello.txt +``` + +--- + +## 3. 常见问题与故障排除 + +| 问题 | 原因 | 解决方案 | +| -------------------------------------- | ------------------------------------ | ----------------------------------------- | +| `S3Exception: 301 Moved Permanently` | 未启用路径风格或区域错误 | 设置 `.forcePathStyle(true)` 并使用区域 `us-east-1` | +| `ConnectException: Connection refused` | RustFS 未启动或端口不正确 | 检查 RustFS 状态和端口 | +| `403 Forbidden` | AccessKey / SecretKey 错误 | 检查身份验证配置 | +| 上传失败且无响应 | SDK 默认使用 HTTPS,而 RustFS 仅支持 HTTP(或需要证书) | 使用 `http://` 地址并配置 `endpointOverride` | + +--- + +## 4. 附录 + +### 4.1 Maven 打包和运行 + +打包项目: + +```bash +mvn clean package +``` + +执行: + +```bash +java -cp target/rustfs-java-s3-demo-1.0-SNAPSHOT.jar com.example.RustfsS3Example +``` + +### 4.2 RustFS 配置建议 + +* 服务使用 HTTP 协议时,确保已禁用 SSL 验证。 +* 如果用于 Web 前端,请启用 CORS 支持。 +* 建议设置 `max_object_size` 和 `max_part_size` 等限制,以防止大文件传输失败。 + +--- + +以下高级示例涵盖: + +* 生成和使用预签名 URL +* 完整的分段上传流程 + +--- + +## 5. Java 高级功能示例 + +### 5.1 生成和使用预签名 URL + +> 预签名 URL 允许客户端在不暴露凭证的情况下临时访问私有对象,广泛用于浏览器直接上传或下载文件等场景。 + +#### 5.1.1 生成下载链接(GET) + +```java +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; +import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; + +import java.net.URI; +import java.time.Duration; + +S3Presigner presigner = S3Presigner.builder() + .endpointOverride(URI.create("http://localhost:9000")) + .region(Region.US_EAST_1) + .credentialsProvider( + StaticCredentialsProvider.create( + AwsBasicCredentials.create("", "") + ) + ) + // The presigner must also sign path-style URLs + .serviceConfiguration( + S3Configuration.builder().pathStyleAccessEnabled(true).build() + ) + .build(); + +GetObjectRequest getObjectRequest = GetObjectRequest.builder() + .bucket("my-bucket") + .key("hello.txt") + .build(); + +GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() + .getObjectRequest(getObjectRequest) + .signatureDuration(Duration.ofMinutes(15)) // 15 minutes validity + .build(); + +PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest); + +System.out.println("Presigned URL: " + presignedRequest.url()); +``` + +```text +Presigned URL: http://localhost:9000/my-bucket/hello.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&... +``` + +> 🔗 在浏览器中打开该链接即可访问对象。 + +#### 5.1.2 上传预签名 URL(PUT) + +同样,你也可以生成上传 URL: + +```java +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest; +import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest; + +PutObjectRequest putRequest = PutObjectRequest.builder() + .bucket("my-bucket") + .key("upload.txt") + .build(); + +PresignedPutObjectRequest presignedPut = presigner.presignPutObject( + PutObjectPresignRequest.builder() + .putObjectRequest(putRequest) + .signatureDuration(Duration.ofMinutes(10)) + .build() +); + +System.out.println("Upload URL: " + presignedPut.url()); +``` + +--- + +### 5.2 实现分段上传 + +> 分段上传是上传大文件的建议方式,可在网络波动时实现断点续传。 + +以下示例复用第 2 节中的 `s3` 客户端,并需要额外导入: + +```java +import software.amazon.awssdk.services.s3.model.*; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +``` + +#### 5.2.1 开始分段上传 + +```java +CreateMultipartUploadRequest createRequest = CreateMultipartUploadRequest.builder() + .bucket("my-bucket") + .key("bigfile.zip") + .build(); + +CreateMultipartUploadResponse createResponse = s3.createMultipartUpload(createRequest); +String uploadId = createResponse.uploadId(); +``` + +#### 5.2.2 上传各分段 + +```java +List completedParts = new ArrayList<>(); +for (int i = 1; i <= 3; i++) { + String partPath = "part" + i + ".bin"; // Assume each part is a local file + UploadPartRequest uploadPartRequest = UploadPartRequest.builder() + .bucket("my-bucket") + .key("bigfile.zip") + .uploadId(uploadId) + .partNumber(i) + .build(); + + UploadPartResponse uploadPartResponse = s3.uploadPart(uploadPartRequest, Paths.get(partPath)); + completedParts.add( + CompletedPart.builder() + .partNumber(i) + .eTag(uploadPartResponse.eTag()) + .build() + ); +} +``` + +#### 5.2.3 完成分段上传 + +```java +CompletedMultipartUpload completedUpload = CompletedMultipartUpload.builder() + .parts(completedParts) + .build(); + +CompleteMultipartUploadRequest completeRequest = CompleteMultipartUploadRequest.builder() + .bucket("my-bucket") + .key("bigfile.zip") + .uploadId(uploadId) + .multipartUpload(completedUpload) + .build(); + +s3.completeMultipartUpload(completeRequest); +System.out.println("Multipart upload completed."); +``` + +```text +Multipart upload completed. +``` + +#### 5.2.4 出现异常时中止上传(可选) + +```java +AbortMultipartUploadRequest abortRequest = AbortMultipartUploadRequest.builder() + .bucket("my-bucket") + .key("bigfile.zip") + .uploadId(uploadId) + .build(); + +s3.abortMultipartUpload(abortRequest); +``` + +--- + +有关其他操作(对象标签、存储桶策略等),请参阅 [AWS SDK for Java v2 文档](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/)。所有 S3 兼容调用都能以相同方式用于 RustFS。 \ No newline at end of file diff --git a/content/zh/developer/sdk/javascript.md b/content/zh/developer/sdk/javascript.md new file mode 100644 index 000000000..e52b763fb --- /dev/null +++ b/content/zh/developer/sdk/javascript.md @@ -0,0 +1,315 @@ +--- +title: "JavaScript SDK 指南" +description: "将官方 AWS SDK for JavaScript v3 与 RustFS 配合使用。" +--- + +## I. 概述 + +RustFS 不提供第一方 JavaScript SDK。RustFS 与 S3 兼容,因此你可以配置官方 AWS SDK for JavaScript(v3),使其指向 RustFS 服务器。本指南介绍如何连接 RustFS 并执行常见的对象存储操作。 + +## II. 前提条件 + +* Node.js 18 或更高版本 +* 一个正在运行的 RustFS 实例(请参阅[安装指南](../../installation/index.md));S3 API 监听端口 `9000`,控制台监听端口 `9001` +* 安装时通过 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` 环境变量设置的访问密钥(请参阅[访问密钥管理](../../security-compliance/iam/access-token.md)) + +:::tip[本地测试] + +如果安装时未设置凭证,服务器默认使用 `rustfsadmin` / `rustfsadmin`。这仅适合一次性本地试用,切勿用于其他人可访问的环境。 + +::: + +### 2.1 安装 SDK + +使用 NPM 安装所需的 AWS SDK v3 模块: + +```bash +npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner +``` + +以下示例使用 ES 模块(`import`)。请在 `package.json` 中设置 `"type": "module"`,或使用 `.mjs` 扩展名保存文件。 + +--- + +## III. 初始化客户端 + +以下是一个可直接运行的完整脚本。如果 RustFS 在另一台计算机上运行,请将 `localhost` 替换为服务器 IP 地址,并填写你自己的访问密钥: + +```js title="main.mjs" +import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3"; + +const s3 = new S3Client({ + endpoint: "http://localhost:9000", // RustFS S3 API address + region: "us-east-1", // RustFS default region + credentials: { + accessKeyId: "", + secretAccessKey: "", + }, + // RustFS uses path-style URLs by default; virtual-host style requires RUSTFS_SERVER_DOMAINS + forcePathStyle: true, +}); + +const { Buckets } = await s3.send(new ListBucketsCommand({})); +console.log(Buckets?.map((b) => b.Name) ?? []); +``` + +运行该脚本: + +```bash +node main.mjs +``` + +```text +[ 'my-bucket' ] +``` + +以下所有代码片段都复用此 `s3` 客户端。 + +--- + +## IV. 基本操作 + +### 4.1 创建存储桶 + +```js +import { CreateBucketCommand } from "@aws-sdk/client-s3"; + +await s3.send(new CreateBucketCommand({ Bucket: "my-bucket" })); +console.log("Bucket created"); +``` + +```text +Bucket created +``` + +--- + +### 4.2 上传对象 + +```js +import { PutObjectCommand } from "@aws-sdk/client-s3"; +import { readFileSync } from "fs"; + +const data = readFileSync("/path/to/hello.txt"); + +await s3.send( + new PutObjectCommand({ + Bucket: "my-bucket", + Key: "hello.txt", + Body: data, + }) +); + +console.log("File uploaded"); +``` + +```text +File uploaded +``` + +--- + +### 4.3 下载对象 + +```js +import { GetObjectCommand } from "@aws-sdk/client-s3"; +import { writeFile } from "fs/promises"; + +const response = await s3.send( + new GetObjectCommand({ Bucket: "my-bucket", Key: "hello.txt" }) +); + +const streamToBuffer = async (stream) => { + const chunks = []; + for await (const chunk of stream) chunks.push(chunk); + return Buffer.concat(chunks); +}; + +const buffer = await streamToBuffer(response.Body); +await writeFile("downloaded.txt", buffer); + +console.log("File downloaded"); +``` + +```text +File downloaded +``` + +--- + +### 4.4 列出对象 + +```js +import { ListObjectsV2Command } from "@aws-sdk/client-s3"; + +const res = await s3.send(new ListObjectsV2Command({ Bucket: "my-bucket" })); +res.Contents?.forEach((obj) => console.log(`${obj.Key} (${obj.Size} bytes)`)); +``` + +```text +hello.txt (12 bytes) +``` + +--- + +### 4.5 删除对象 + +```js +import { DeleteObjectCommand } from "@aws-sdk/client-s3"; + +await s3.send(new DeleteObjectCommand({ Bucket: "my-bucket", Key: "hello.txt" })); +console.log("File deleted"); +``` + +```text +File deleted +``` + +--- + +## V. 高级功能 + +### 5.1 生成预签名 URL + +> 允许前端或第三方使用临时链接上传或下载文件 + +#### 下载(GET) + +```js +import { GetObjectCommand } from "@aws-sdk/client-s3"; +import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; + +const url = await getSignedUrl( + s3, + new GetObjectCommand({ Bucket: "my-bucket", Key: "hello.txt" }), + { expiresIn: 600 } +); + +console.log("Presigned GET URL:", url); +``` + +```text +Presigned GET URL: http://localhost:9000/my-bucket/hello.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&... +``` + +#### 上传(PUT) + +```js +import { PutObjectCommand } from "@aws-sdk/client-s3"; +import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; + +const url = await getSignedUrl( + s3, + new PutObjectCommand({ Bucket: "my-bucket", Key: "upload.txt" }), + { expiresIn: 600 } +); + +console.log("Presigned PUT URL:", url); +``` + +--- + +### 5.2 分段上传 + +```js +import { + CreateMultipartUploadCommand, + UploadPartCommand, + CompleteMultipartUploadCommand, + AbortMultipartUploadCommand, +} from "@aws-sdk/client-s3"; +import { statSync, openSync, readSync, closeSync } from "fs"; + +const bucket = "my-bucket"; +const key = "large-file.zip"; +const filePath = "./large-file.zip"; +const partSize = 5 * 1024 * 1024; // 5 MB + +// 1. Create upload task +const createRes = await s3.send( + new CreateMultipartUploadCommand({ Bucket: bucket, Key: key }) +); +const uploadId = createRes.UploadId; + +// 2. Segmented upload +const fileSize = statSync(filePath).size; +const fd = openSync(filePath, "r"); +const parts = []; + +for (let partNumber = 1, offset = 0; offset < fileSize; partNumber++) { + const buffer = Buffer.alloc(Math.min(partSize, fileSize - offset)); + readSync(fd, buffer, 0, buffer.length, offset); + + const uploadPartRes = await s3.send( + new UploadPartCommand({ + Bucket: bucket, + Key: key, + UploadId: uploadId, + PartNumber: partNumber, + Body: buffer, + }) + ); + + parts.push({ ETag: uploadPartRes.ETag, PartNumber: partNumber }); + offset += partSize; +} + +closeSync(fd); + +// 3. Complete upload +await s3.send( + new CompleteMultipartUploadCommand({ + Bucket: bucket, + Key: key, + UploadId: uploadId, + MultipartUpload: { Parts: parts }, + }) +); + +console.log("Multipart upload completed"); +``` + +```text +Multipart upload completed +``` + +--- + +## VI. 常见问题和注意事项 + +| 问题 | 原因 | 解决方案 | +| --------------------------- | -------------------- | --------------------------------------- | +| SignatureDoesNotMatch | 签名版本错误 | JS SDK v3 默认使用 v4,请确保 RustFS 支持 v4 | +| EndpointConnectionError | 端点地址配置错误或服务未启动 | 检查 RustFS 地址是否可访问 | +| NoSuchKey | 文件不存在 | 检查 `Key` 拼写是否正确 | +| InvalidAccessKeyId / Secret | 凭证配置错误 | 检查 `accessKeyId` / `secretAccessKey` 配置 | +| 上传失败(路径问题) | 未启用路径风格 | 设置 `forcePathStyle: true` | + +--- + +## VII. 附录:适配前端上传 + +使用预签名 URL 后,浏览器可以在不传递 AccessKey 的情况下直接上传文件。 + +前端(HTML+JS)上传示例: + +```html + + +``` + +有关其他操作(对象标签、存储桶策略等),请参阅 [AWS SDK for JavaScript v3 文档](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/)。所有 S3 兼容调用都能以相同方式用于 RustFS。 \ No newline at end of file diff --git a/content/zh/developer/sdk/meta.json b/content/zh/developer/sdk/meta.json new file mode 100644 index 000000000..616372356 --- /dev/null +++ b/content/zh/developer/sdk/meta.json @@ -0,0 +1,12 @@ +{ + "title": "SDK", + "pages": [ + "[Java](/zh/developer/sdk/java)", + "[Python](/zh/developer/sdk/python)", + "[Rust](/zh/developer/sdk/rust)", + "[JavaScript](/zh/developer/sdk/javascript)", + "[TypeScript](/zh/developer/sdk/typescript)", + "[Golang](/zh/developer/sdk/go)", + "[其他 SDK](/zh/developer/sdk/other)" + ] +} diff --git a/content/zh/developer/sdk/other.md b/content/zh/developer/sdk/other.md new file mode 100644 index 000000000..9f7b7bb2b --- /dev/null +++ b/content/zh/developer/sdk/other.md @@ -0,0 +1,78 @@ +--- +title: "其他 SDK" +description: "介绍如何在 RustFS 中使用其他语言的 SDK。" +--- + +如果 AWS S3 未正式支持你的编程语言,可以采用以下策略与 RustFS 集成: + +## 1. 直接请求 HTTP 接口(基于 S3 API 协议) + +S3 协议是一套标准 RESTful API。你可以使用任何支持 HTTP 请求的语言(例如 C、Rust、Lua、Erlang)自行封装访问逻辑。 + +### 要点包括: + +* **签名算法**:实现 AWS Signature Version 4 签名(较复杂) +* **构造正确的标头和规范请求** +* **使用 HTTPS/HTTP 客户端发送请求** + +👉 建议参考开源项目的签名实现,例如: + +* [https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html](https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html) + +--- + +## 2. 调用现有 SDK 的 CLI 工具或中间件服务 + +如果不想自行实现签名,可以: + +### 2.1. 使用已有语言支持调用 AWS CLI 工具: + +例如,通过 Shell 调用: + +```bash +aws s3 cp local.txt s3://mybucket/myfile.txt --endpoint-url http://rustfs.local:9000 +``` + +或者使用 Node.js/Python SDK 编写简单的中继服务,让你的语言通过调用该服务上传或下载文件。 + +### 2.2. 设置代理(例如 Flask、FastAPI、Express) + +让不支持 S3 的客户端调用你封装的 HTTP API: + +```http +POST /upload -> Service internally calls SDK to upload objects to RustFS +GET /presigned-url -> Generate presigned URL for frontend/client use +``` + +--- + +## 3. 寻找第三方社区 SDK + +虽然 AWS 没有提供官方 SDK,但部分语言社区开发了非官方 S3 客户端。例如: + +* Haskell:`amazonka-s3` +* Rust:`rusoto`(已弃用)或 `aws-sdk-rust` +* OCaml:可通过 `cohttp` 自行实现 +* Delphi:有支持 S3 协议的商业库 + +社区 SDK 的稳定性差异很大,因此使用前应评估其活跃度、文档和兼容性。 + +--- + +## 4. 将核心上传逻辑交由平台托管 + +例如: + +* 将前端(Web/移动端)上传任务交给浏览器或 App 端执行(使用预签名 URL) +* 后端使用 Node.js/Python/Go 等代理实现上传逻辑 + +--- + +## 建议汇总 + +| 场景 | 建议方案 | +| ------------- | ---------------------------------- | +| 需要完全控制或使用嵌入式环境 | 自行实现 Signature V4 签名 | +| 语言支持较弱但可使用 Shell | 通过 AWS CLI 调用上传 | +| 可以部署中继服务 | 使用 Python/Node 构建 S3 API 网关 | +| 前端上传 | 使用预签名 URL | \ No newline at end of file diff --git a/content/zh/developer/sdk/python.md b/content/zh/developer/sdk/python.md new file mode 100644 index 000000000..fd6f81731 --- /dev/null +++ b/content/zh/developer/sdk/python.md @@ -0,0 +1,287 @@ +--- +title: "Python SDK 指南" +description: "将官方 AWS SDK for Python(Boto3)与 RustFS 配合使用。" +--- + +## 1. 概述 + +RustFS 不提供第一方 SDK。RustFS 与 S3 兼容,因此你可以配置官方 AWS SDK for Python [Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html),使其指向 RustFS 服务器。 + +本指南涵盖: + +* 创建和删除存储桶 +* 上传、下载和删除对象 +* 列出对象 +* 生成预签名 URL +* 对大文件执行分段上传 + +--- + +## 2. 前提条件 + +* Python 3.8 或更高版本 +* 一个正在运行的 RustFS 实例(请参阅[安装指南](../../installation/index.md));S3 API 监听端口 `9000`,控制台监听端口 `9001` +* 安装时通过 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` 环境变量设置的访问密钥(请参阅[访问密钥管理](../../security-compliance/iam/access-token.md)) + +:::tip[本地测试] + +如果安装时未设置凭证,服务器默认使用 `rustfsadmin` / `rustfsadmin`。这仅适合一次性本地试用,切勿用于其他人可访问的环境。 + +::: + +### 2.1 安装 Boto3 + +我们建议使用虚拟环境: + +```bash +python3 -m venv venv +source venv/bin/activate +pip install boto3 +``` + +> Boto3 依赖 `botocore`,后者会自动安装。 + +--- + +## 3. 连接到 RustFS + +以下是一个可直接运行的完整脚本。如果 RustFS 在另一台计算机上运行,请将 `localhost` 替换为服务器 IP 地址,并填写你自己的访问密钥: + +```python title="main.py" +import boto3 +from botocore.client import Config + +s3 = boto3.client( + 's3', + endpoint_url='http://localhost:9000', + aws_access_key_id='', + aws_secret_access_key='', + region_name='us-east-1', + config=Config( + signature_version='s3v4', + s3={'addressing_style': 'path'}, + ), +) + +response = s3.list_buckets() +for bucket in response['Buckets']: + print(bucket['Name']) +``` + +运行该脚本: + +```bash +python main.py +``` + +:::note[客户端参数说明] + +- `endpoint_url`:指向 RustFS S3 API(端口 `9000`,而不是控制台端口 `9001`) +- `signature_version='s3v4'`:RustFS 支持 v4 签名 +- `region_name='us-east-1'`:RustFS 的默认区域 +- `addressing_style='path'`:RustFS 默认使用路径风格 URL;虚拟主机风格需要配置 `RUSTFS_SERVER_DOMAINS` + +::: + +--- + +## 4. 基本操作 + +### 4.1 创建存储桶 + +```python +bucket_name = 'my-bucket' + +try: + s3.create_bucket(Bucket=bucket_name) + print(f'Bucket {bucket_name} created.') +except s3.exceptions.BucketAlreadyOwnedByYou: + print(f'Bucket {bucket_name} already exists.') +``` + +```text +Bucket my-bucket created. +``` + +--- + +### 4.2 上传文件 + +```python +s3.upload_file('/path/to/hello.txt', bucket_name, 'hello.txt') +print('File uploaded.') +``` + +```text +File uploaded. +``` + +--- + +### 4.3 下载文件 + +```python +s3.download_file(bucket_name, 'hello.txt', 'hello-downloaded.txt') +print('File downloaded.') +``` + +```text +File downloaded. +``` + +--- + +### 4.4 列出对象 + +```python +response = s3.list_objects_v2(Bucket=bucket_name) +for obj in response.get('Contents', []): + print(f"- {obj['Key']} ({obj['Size']} bytes)") +``` + +```text +- hello.txt (12 bytes) +``` + +--- + +### 4.5 删除对象和存储桶 + +```python +s3.delete_object(Bucket=bucket_name, Key='hello.txt') +print('Object deleted.') + +s3.delete_bucket(Bucket=bucket_name) +print('Bucket deleted.') +``` + +```text +Object deleted. +Bucket deleted. +``` + +--- + +## 5. 高级功能 + +### 5.1 生成预签名 URL + +#### 5.1.1 下载链接(GET) + +```python +url = s3.generate_presigned_url( + ClientMethod='get_object', + Params={'Bucket': bucket_name, 'Key': 'hello.txt'}, + ExpiresIn=600, # 10 minutes validity +) + +print('Presigned GET URL:', url) +``` + +```text +Presigned GET URL: http://localhost:9000/my-bucket/hello.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&... +``` + +#### 5.1.2 上传链接(PUT) + +```python +url = s3.generate_presigned_url( + ClientMethod='put_object', + Params={'Bucket': bucket_name, 'Key': 'upload-by-url.txt'}, + ExpiresIn=600, +) + +print('Presigned PUT URL:', url) +``` + +你可以使用 `curl` 工具上传: + +```bash +curl -X PUT --upload-file /path/to/hello.txt "http://localhost:9000/my-bucket/upload-by-url.txt?X-Amz-Algorithm=..." +``` + +--- + +### 5.2 分段上传 + +适用于大于 10 MB 的文件,并允许手动控制每个分段。 + +```python +file_path = 'largefile.bin' +key = 'largefile.bin' +part_size = 5 * 1024 * 1024 # 5 MB + +# 1. Start upload +response = s3.create_multipart_upload(Bucket=bucket_name, Key=key) +upload_id = response['UploadId'] +parts = [] + +try: + with open(file_path, 'rb') as f: + part_number = 1 + while True: + data = f.read(part_size) + if not data: + break + + part = s3.upload_part( + Bucket=bucket_name, + Key=key, + PartNumber=part_number, + UploadId=upload_id, + Body=data, + ) + + parts.append({'ETag': part['ETag'], 'PartNumber': part_number}) + print(f'Uploaded part {part_number}') + part_number += 1 + + # 2. Complete upload + s3.complete_multipart_upload( + Bucket=bucket_name, + Key=key, + UploadId=upload_id, + MultipartUpload={'Parts': parts}, + ) + print('Multipart upload complete.') + +except Exception as e: + # Abort upload + s3.abort_multipart_upload(Bucket=bucket_name, Key=key, UploadId=upload_id) + print('Multipart upload aborted due to error:', e) +``` + +```text +Uploaded part 1 +Uploaded part 2 +Uploaded part 3 +Multipart upload complete. +``` + +--- + +## 6. 常见问题排查 + +| 问题 | 原因 | 解决方案 | +| ------------------------- | ----------------- | -------------------------------------------------------------- | +| `SignatureDoesNotMatch` | 未使用 v4 签名 | 设置 `signature_version='s3v4'` | +| `EndpointConnectionError` | RustFS 地址错误或服务未启动 | 检查端点和 RustFS 服务状态 | +| `AccessDenied` | 凭证错误或权限不足 | 检查 AccessKey/SecretKey 或存储桶策略 | +| `PermanentRedirect` / 存储桶 URL 错误 | 未启用路径风格 | 在 `Config` 中设置 `s3={'addressing_style': 'path'}` | + +--- + +## 7. 附录:快速上传/下载脚本模板 + +```python +def upload_file(local_path, bucket, object_key): + s3.upload_file(local_path, bucket, object_key) + print(f"Uploaded {local_path} to s3://{bucket}/{object_key}") + + +def download_file(bucket, object_key, local_path): + s3.download_file(bucket, object_key, local_path) + print(f"Downloaded s3://{bucket}/{object_key} to {local_path}") +``` + +有关其他操作(对象标签、存储桶策略等),请参阅 [Boto3 S3 文档](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)。所有 S3 兼容调用都能以相同方式用于 RustFS。 \ No newline at end of file diff --git a/content/zh/developer/sdk/rust.md b/content/zh/developer/sdk/rust.md new file mode 100644 index 000000000..26feb1185 --- /dev/null +++ b/content/zh/developer/sdk/rust.md @@ -0,0 +1,287 @@ +--- +title: "Rust SDK 指南" +description: "通过 AWS SDK for Rust 操作 RustFS 实例,包括创建和删除存储桶与对象。" +--- + +RustFS 不提供第一方 Rust 客户端 crate。RustFS 与 S3 完全兼容,因此你可以配置官方 AWS SDK for Rust(`aws-sdk-s3`),使其指向 RustFS 服务器。通过该 SDK,你可以操作 RustFS,包括创建和删除存储桶或对象、上传和下载文件等。 + +## 前提条件 + +- Rust 1.78 或更高版本(通过 [rustup](https://rustup.rs/) 安装) +- 一个可用的 RustFS 实例(请参阅[安装指南](../../installation/index.md));S3 API 监听端口 `9000`,控制台监听端口 `9001` +- 安装时通过 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` 环境变量设置的访问密钥(请参阅[访问密钥管理](../../security-compliance/iam/access-token.md)) + +:::tip[本地测试] + +如果安装时未设置凭证,服务器默认使用 `rustfsadmin` / `rustfsadmin`。这仅适合一次性本地试用,切勿用于其他人可访问的环境。 + +::: + +创建项目并添加依赖项: + +```bash +cargo new rustfs-rust-demo && cd rustfs-rust-demo +cargo add aws-config aws-sdk-s3 anyhow +cargo add tokio --features full +``` + +你的 `Cargo.toml` 应包含: + +```toml title="Cargo.toml" +[dependencies] +anyhow = "1" +aws-config = "1" +aws-sdk-s3 = "1" +tokio = { version = "1", features = ["full"] } +``` + +## 初始化客户端 + +以下是一个可直接运行的完整程序。它从环境变量加载连接设置、初始化 S3 客户端并列出存储桶: + +```rust title="src/main.rs" +use anyhow::Result; +use aws_config::BehaviorVersion; +use aws_sdk_s3::config::{Credentials, Region}; +use aws_sdk_s3::Client; +use std::env; + +pub struct Config { + pub region: String, + pub access_key_id: String, + pub secret_access_key: String, + pub endpoint_url: String, +} + +impl Config { + pub fn from_env() -> Result { + let region = env::var("RUSTFS_REGION")?; + let access_key_id = env::var("RUSTFS_ACCESS_KEY_ID")?; + let secret_access_key = env::var("RUSTFS_SECRET_ACCESS_KEY")?; + let endpoint_url = env::var("RUSTFS_ENDPOINT_URL")?; + + Ok(Config { + region, + access_key_id, + secret_access_key, + endpoint_url, + }) + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let config = Config::from_env()?; + + let credentials = Credentials::new( + config.access_key_id, + config.secret_access_key, + None, + None, + "rustfs", + ); + + let region = Region::new(config.region); + + let shared_config = aws_config::defaults(BehaviorVersion::latest()) + .region(region) + .credentials_provider(credentials) + .endpoint_url(config.endpoint_url) + .load() + .await; + + // RustFS uses path-style URLs by default; virtual-host style requires RUSTFS_SERVER_DOMAINS + let s3_config = aws_sdk_s3::config::Builder::from(&shared_config) + .force_path_style(true) + .build(); + + let rustfs_client = Client::from_conf(s3_config); + + let res = rustfs_client.list_buckets().send().await?; + for bucket in res.buckets() { + println!("Bucket: {:?}", bucket.name()); + } + + Ok(()) +} +``` + +:::note + +这些环境变量名(`RUSTFS_ENDPOINT_URL`、`RUSTFS_REGION`、`RUSTFS_ACCESS_KEY_ID`、`RUSTFS_SECRET_ACCESS_KEY`)只是本示例的客户端约定,由你的程序读取,而不是由 RustFS 读取。它们不同于安装 RustFS 时使用的服务器端变量 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY`。 + +::: + +运行该程序(如果 RustFS 在另一台计算机上运行,请将 `localhost` 替换为服务器 IP 地址): + +```bash +export RUSTFS_ENDPOINT_URL="http://localhost:9000" +export RUSTFS_REGION="us-east-1" +export RUSTFS_ACCESS_KEY_ID="" +export RUSTFS_SECRET_ACCESS_KEY="" +cargo run +``` + +```text +Bucket: Some("my-bucket") +``` + +现在可以使用该客户端执行以下操作。每个代码片段都在 `main` 内运行,并复用 `rustfs_client`。 + +## 创建存储桶 + +```rust +match rustfs_client + .create_bucket() + .bucket("my-bucket") + .send() + .await +{ + Ok(_) => { + println!("Bucket created successfully"); + } + Err(e) => { + println!("Error creating bucket: {:?}", e); + return Err(e.into()); + } +} +``` + +```text +Bucket created successfully +``` + +## 删除存储桶 + +```rust +match rustfs_client + .delete_bucket() + .bucket("my-bucket") + .send() + .await +{ + Ok(_) => { + println!("Bucket deleted successfully"); + } + Err(e) => { + println!("Error deleting bucket: {:?}", e); + return Err(e.into()); + } +} +``` + +```text +Bucket deleted successfully +``` + +## 列出存储桶 + +```rust +match rustfs_client.list_buckets().send().await { + Ok(res) => { + println!("Total buckets number is {:?}", res.buckets().len()); + for bucket in res.buckets() { + println!("Bucket: {:?}", bucket.name()); + } + } + Err(e) => { + println!("Error listing buckets: {:?}", e); + return Err(e.into()); + } +} +``` + +```text +Total buckets number is 1 +Bucket: Some("my-bucket") +``` + +## 列出对象 + +```rust +match rustfs_client + .list_objects_v2() + .bucket("my-bucket") + .send() + .await +{ + Ok(res) => { + println!("Total objects number is {:?}", res.contents().len()); + for object in res.contents() { + println!("Object: {:?}", object.key()); + } + } + Err(e) => { + println!("Error listing objects: {:?}", e); + return Err(e.into()); + } +} +``` + +```text +Total objects number is 1 +Object: Some("hello.txt") +``` + +## 上传文件 + +在 `src/main.rs` 顶部添加以下导入: + +```rust +use aws_sdk_s3::primitives::ByteStream; +use tokio::fs; +``` + +然后上传本地文件: + +```rust +let data = fs::read("/path/to/hello.txt").await.expect("can not open the file"); + +match rustfs_client + .put_object() + .bucket("my-bucket") + .key("hello.txt") + .body(ByteStream::from(data)) + .send() + .await +{ + Ok(res) => { + println!("Object uploaded successfully, res: {:?}", res); + } + Err(e) => { + println!("Error uploading object: {:?}", e); + return Err(e.into()); + } +} +``` + +```text +Object uploaded successfully, res: PutObjectOutput { e_tag: Some("\"...\""), ... } +``` + +## 下载对象 + +```rust +match rustfs_client + .get_object() + .bucket("my-bucket") + .key("hello.txt") + .send() + .await +{ + Ok(res) => { + let data = res.body.collect().await?.into_bytes(); + println!("Object content: {}", String::from_utf8_lossy(&data)); + } + Err(e) => { + println!("Error downloading object: {:?}", e); + return Err(e.into()); + } +} +``` + +```text +Object content: hello rustfs +``` + +有关其他操作(预签名 URL、分段上传等),请参阅 [AWS SDK for Rust 文档](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/)。所有 S3 兼容调用都能以相同方式用于 RustFS。 \ No newline at end of file diff --git a/content/zh/developer/sdk/typescript.md b/content/zh/developer/sdk/typescript.md new file mode 100644 index 000000000..910d46a87 --- /dev/null +++ b/content/zh/developer/sdk/typescript.md @@ -0,0 +1,204 @@ +--- +title: "RustFS TypeScript SDK 使用指南" +description: "通过 AWS SDK for JavaScript v3 从 TypeScript 操作 RustFS,包括创建和删除存储桶与对象。" +--- + +RustFS 不提供第一方 TypeScript SDK。RustFS 与 S3 兼容,因此你可以配置自带 TypeScript 类型定义的官方 AWS SDK for JavaScript v3,使其指向 RustFS 服务器。通过该 SDK,你可以操作 RustFS,包括创建和删除存储桶或对象、上传和下载文件等。 + +## 前提条件 + +- Node.js 18 或更高版本(示例使用 ES 模块,请将 `"type": "module"` 写入 `package.json`) +- 一个可用的 RustFS 实例(安装方法请参阅[安装指南](../../installation/index.md));S3 API 监听端口 `9000`,控制台监听端口 `9001` +- 安装时通过 `RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY` 环境变量设置的访问密钥(创建方法请参阅[访问密钥管理](../../security-compliance/iam/access-token.md)) + +:::tip[本地测试] + +如果安装时未设置凭证,服务器默认使用 `rustfsadmin` / `rustfsadmin`。这仅适合一次性本地试用,切勿用于其他人可访问的环境。 + +::: + +安装依赖项: + +```bash +npm install @aws-sdk/client-s3 +npm install --save-dev typescript tsx @types/node +``` + +## 初始化客户端 + +以下是一个可直接运行的完整示例。如果 RustFS 在另一台计算机上运行,请将 `localhost` 替换为服务器 IP 地址,并填写你自己的访问密钥: + +```typescript title="main.ts" +import { + S3Client, + CreateBucketCommand, + DeleteBucketCommand, + ListBucketsCommand, + ListObjectsV2Command, + PutObjectCommand, + GetObjectCommand, +} from "@aws-sdk/client-s3"; +import * as fs from "fs"; + +const rustfs_client = new S3Client({ + region: "us-east-1", // RustFS default region + endpoint: "http://localhost:9000", // RustFS S3 API address + credentials: { + accessKeyId: "", + secretAccessKey: "", + }, + // RustFS uses path-style URLs by default; virtual-host style requires RUSTFS_SERVER_DOMAINS + forcePathStyle: true, +}); + +const response = await rustfs_client.send(new ListBucketsCommand({})); +console.log(response.Buckets?.map((bucket) => bucket.Name) ?? []); +``` + +运行该示例: + +```bash +npx tsx main.ts +``` + +```text +[ 'my-bucket' ] +``` + +然后使用已构造的 `rustfs_client` 执行以下操作。 + +## 创建存储桶 + +```typescript +async function createBucket() { + try { + const response = await rustfs_client.send( + new CreateBucketCommand({ + Bucket: "my-bucket", + }) + ); + console.log("Bucket created:", response.Location); + } catch (error) { + console.log(error); + } +} +``` + +```text +Bucket created: /my-bucket +``` + +## 删除存储桶 + +```typescript +async function deleteBucket() { + try { + await rustfs_client.send( + new DeleteBucketCommand({ + Bucket: "my-bucket", + }) + ); + console.log("Bucket deleted"); + } catch (error) { + console.log(error); + } +} +``` + +```text +Bucket deleted +``` + +## 列出存储桶 + +```typescript +async function listBuckets() { + try { + const response = await rustfs_client.send(new ListBucketsCommand({})); + response.Buckets?.forEach((bucket) => console.log(bucket.Name)); + } catch (error) { + console.log(error); + } +} +``` + +```text +my-bucket +``` + +## 列出对象 + +```typescript +async function listObjects() { + try { + const response = await rustfs_client.send( + new ListObjectsV2Command({ + Bucket: "my-bucket", + }) + ); + response.Contents?.forEach((obj) => console.log(`${obj.Key} (${obj.Size} bytes)`)); + } catch (error) { + console.log(error); + } +} +``` + +```text +test/hello.txt (12 bytes) +``` + +## 上传文件 + +```typescript +async function uploadFile() { + try { + await rustfs_client.send( + new PutObjectCommand({ + Bucket: "my-bucket", + Key: "test/hello.txt", + Body: fs.createReadStream("/path/to/hello.txt"), + }) + ); + console.log("Object uploaded"); + } catch (error) { + console.log(error); + } +} +``` + +```text +Object uploaded +``` + +## 下载对象 + +```typescript +async function getObject() { + try { + const response = await rustfs_client.send( + new GetObjectCommand({ + Bucket: "my-bucket", + Key: "test/hello.txt", + }) + ); + + // get object content + if (response.Body) { + const chunks: Buffer[] = []; + for await (const chunk of response.Body as any) { + chunks.push(chunk as Buffer); + } + const data = Buffer.concat(chunks).toString("utf-8"); + console.log("Object content:", data); + } + } catch (error) { + console.log(error); + } +} +``` + +```text +Object content: hello rustfs +``` + +有关其他操作(预签名 URL、分段上传等),请参阅 [AWS SDK for JavaScript v3 文档](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/)。所有 S3 兼容调用都能以相同方式用于 RustFS。 \ No newline at end of file diff --git a/content/zh/index.mdx b/content/zh/index.mdx new file mode 100644 index 000000000..132feb56a --- /dev/null +++ b/content/zh/index.mdx @@ -0,0 +1,82 @@ +--- +title: "RustFS 文档" +description: "了解如何安装、配置、管理和维护 RustFS。" +--- + +
+
+
+ RustFS 是使用 Rust 编写的分布式对象存储系统,面向兼容 S3 的工作负载。 + 本文档涵盖 RustFS 集群的安装、管理、安全配置和日常运维。 +
+
+ 查看安装要求 + +
+ +
+ + + + 在 Linux 上安装 + 从 Linux 服务器开始,然后选择单节点或分布式部署拓扑。 + + + + + + + 使用 Docker 安装 + 以容器方式运行 RustFS,用于本地评估或托管部署。 + + + + + + + 使用 Podman 安装 + 使用 Podman 部署无需 root 权限、无需守护进程的 RustFS 容器。 + + + + + + + 使用 Helm 安装 + 使用 RustFS Helm Chart 在 Kubernetes 上部署 RustFS 集群。 + + + + + + + 使用 Operator 安装 + 管理 Kubernetes 原生的 RustFS 租户、存储池和生命周期操作。 + + + + + + + 在 macOS 上安装 + 在 Apple 芯片或 Intel 芯片的 Mac 电脑上运行 RustFS。 + + + + + + + 在 Windows 上安装 + 在受支持的 Windows 环境中安装并运行 RustFS。 + + +
+
diff --git a/content/zh/installation/cloud-native/helm-chart/cert-manager.md b/content/zh/installation/cloud-native/helm-chart/cert-manager.md new file mode 100644 index 000000000..4b26dd45e --- /dev/null +++ b/content/zh/installation/cloud-native/helm-chart/cert-manager.md @@ -0,0 +1,69 @@ +--- +title: cert-manager +description: 使用 cert-manager 为 RustFS Helm 部署签发和续订 TLS 证书。 +--- + +使用 **cert-manager** 签发 RustFS Ingress 引用的证书。这样可以为公共 S3 API 和控制台端点提供 HTTPS,并允许 cert-manager 续订证书。 + +## 环境要求 + +- cert-manager 已安装,且其控制器 Pod 已就绪。 +- `Issuer` 或 `ClusterIssuer` 已就绪。 +- RustFS 主机名可解析到 Ingress 控制器。 + +安装 RustFS 前验证 issuer: + +```bash +kubectl get clusterissuer letsencrypt-prod +kubectl -n cert-manager get pods +``` + +## 1. 配置 Ingress TLS + +将 Ingress 和证书设置添加到单机或分布式 values 文件: + +```yaml title="values.yaml" +ingress: + enabled: true + className: nginx + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + hosts: + - host: s3.example.com + paths: + - path: / + pathType: Prefix + tls: + enabled: true + certManager: + enabled: true + existingSecret: + enabled: false + name: "" +``` + +请根据集群替换 Ingress class、issuer 和主机名。对于命名空间级 Issuer,请改用 `cert-manager.io/issuer` 注解。 + +## 2. 应用配置 + +```bash +helm upgrade rustfs ./helm/rustfs \ + --namespace rustfs \ + -f values.yaml +``` + +对于名为 `rustfs` 的 release,Ingress 会引用 `rustfs-tls` Secret。cert-manager ingress-shim 读取 issuer 注解并创建 Certificate,将证书写入此 Secret。 + +## 3. 验证证书 + +```bash +kubectl -n rustfs get ingress,certificate,certificaterequest +kubectl -n rustfs describe certificate rustfs-tls +kubectl -n rustfs get secret rustfs-tls +``` + +等待 Certificate 报告 `Ready=True`,然后打开 `https://s3.example.com`。 + +## 将 cert-manager 与 mTLS 配合使用 + +启用 `mtls.enabled=true` 后,该 chart 也会使用 cert-manager 签发服务器和客户端证书。请参阅 [mTLS](./mtls.md),了解如何使用 chart 管理的 CA 或引用现有 issuer。 \ No newline at end of file diff --git a/content/zh/installation/cloud-native/helm-chart/index.md b/content/zh/installation/cloud-native/helm-chart/index.md new file mode 100644 index 000000000..af3bd8480 --- /dev/null +++ b/content/zh/installation/cloud-native/helm-chart/index.md @@ -0,0 +1,21 @@ +--- +title: 概述 +description: 了解 RustFS Helm chart 如何在 Kubernetes 上部署单机和分布式集群。 +--- + +官方 **RustFS Helm chart** 可将一个 RustFS 集群直接部署到 Kubernetes 中。Helm 根据单个 values 文件渲染工作负载、Service、凭证、配置、PersistentVolumeClaim(PVC)、Ingress 以及可选的证书资源。 + +该 chart 支持两种部署模式: + +- **单机模式**会创建一个包含一个数据 PVC 的 Pod,适用于评估和开发。 +- **分布式模式**会创建包含多个 Pod 和数据 PVC 的 StatefulSet。`replicaCount` 控制 Pod 数量,`drivesPerNode` 控制每个 Pod 挂载的数据 PVC 数量。 + +默认启用分布式模式。该 chart 还支持多个仅追加的服务器池,但对于首次部署,明确使用单一拓扑更易于运维。必须通过 chart values 或现有 Secret 提供凭证;除非明确启用不安全的开发默认值,否则 chart 会拒绝空凭证和众所周知的默认凭证。 + +需要使用 Helm 管理一个 RustFS 集群时,请使用 Helm chart。需要 Kubernetes 自定义资源、多租户或由 Operator 管理存储池时,请使用 [RustFS Operator](../operator/index.md)。 + +## Helm chart 工作流 + +- [安装](./installation.mdx)介绍环境要求以及单机或分布式部署。 +- [mTLS](./mtls.md)用于加密 RustFS Pod 之间的流量并验证通信双方身份。 +- [cert-manager](./cert-manager.md)为 RustFS Ingress 和 mTLS 签发并续订证书。 \ No newline at end of file diff --git a/content/zh/installation/cloud-native/helm-chart/installation.mdx b/content/zh/installation/cloud-native/helm-chart/installation.mdx new file mode 100644 index 000000000..b79a1cfb0 --- /dev/null +++ b/content/zh/installation/cloud-native/helm-chart/installation.mdx @@ -0,0 +1,168 @@ +--- +title: 安装 +description: 使用官方 Helm chart 在 Kubernetes 上安装单机或分布式 RustFS。 +--- + +本指南介绍如何从源代码或 Helm 仓库获取官方 RustFS chart、完成安装,并验证对 S3 API 和控制台的访问。 + +## 环境要求 + +| 组件 | 要求 | +|-----------|-------------| +| Helm | 版本 3 | +| Kubernetes | 可通过 `kubectl` 访问的集群 | +| StorageClass | 为 RustFS 数据动态预配 PVC | +| RustFS | `1.0.0-alpha.69` 或更高版本 | + +Ingress 控制器为可选组件。如果启用 Ingress,请将 `ingress.className` 设置为集群中的控制器,例如 `nginx` 或 `traefik`。 + +检查当前集群和可用的 StorageClass: + +```bash +kubectl config current-context +kubectl get storageclass +helm version --short +``` + +## 1. 获取 chart + +选择 Helm 访问 chart 的方式。两个选项都会设置 `RUSTFS_CHART`,供后续安装命令使用。 + + + + +克隆 RustFS 源代码仓库,使用 `helm/rustfs` 中的 chart: + +```bash +git clone https://github.com/rustfs/rustfs.git +cd rustfs +export RUSTFS_CHART=./helm/rustfs +``` + + + + +添加 [Artifact Hub](https://artifacthub.io/packages/helm/rustfs/rustfs) 上列出的 RustFS 仓库,然后更新本地仓库索引: + +```bash +helm repo add rustfs https://charts.rustfs.com +helm repo update +export RUSTFS_CHART=rustfs/rustfs +``` + + + + +## 2. 安装单机模式 + +为单 Pod 开发部署创建 values 文件: + +```yaml title="standalone-values.yaml" +mode: + standalone: + enabled: true + distributed: + enabled: false + +secret: + rustfs: + access_key: "" + secret_key: "" + +storageclass: + name: standard + dataStorageSize: 10Gi + logStorageSize: 1Gi + +ingress: + enabled: false +``` + +将 `standard` 替换为集群中的 StorageClass,然后安装: + +```bash +helm upgrade --install rustfs "$RUSTFS_CHART" \ + --namespace rustfs \ + --create-namespace \ + -f standalone-values.yaml +``` + +## 3. 安装分布式模式 + +对于分布式集群,请显式设置 Pod 和驱动器数量。数据驱动器总数等于 `replicaCount * drivesPerNode`。 + +```yaml title="distributed-values.yaml" +mode: + standalone: + enabled: false + distributed: + enabled: true + +replicaCount: 4 +drivesPerNode: 2 + +secret: + rustfs: + access_key: "" + secret_key: "" + +storageclass: + name: standard + dataStorageSize: 100Gi + logStorageSize: 1Gi + +ingress: + enabled: false +``` + +该示例创建四个 Pod 和八个数据 PVC。确保集群可以调度所有 Pod 并预配所有 PVC,然后安装: + +```bash +helm upgrade --install rustfs "$RUSTFS_CHART" \ + --namespace rustfs \ + --create-namespace \ + -f distributed-values.yaml +``` + +:::warning[安装前选择拓扑] + +Kubernetes 不允许更新 StatefulSet `volumeClaimTemplates`。以后更改 `drivesPerNode` 需要重新创建 StatefulSet 或重新安装。 + +::: + +## 4. 验证并访问 RustFS + +```bash +kubectl -n rustfs get pods,pvc,services +kubectl -n rustfs rollout status statefulset/rustfs +``` + +单机模式创建 Deployment,而不是 StatefulSet。使用以下命令检查: + +```bash +kubectl -n rustfs rollout status deployment/rustfs +``` + +将 S3 API 和控制台转发到工作站: + +```bash +kubectl -n rustfs port-forward svc/rustfs 9000:9000 9001:9001 +``` + +将 `http://localhost:9000` 用作 S3 端点,并打开 `http://localhost:9001` 访问控制台。 + +## 关键值 + +| 值 | 用途 | Chart 默认值 | +|-------|---------|---------------| +| `mode.standalone.enabled` | 启用单 Pod 单机模式 | `false` | +| `mode.distributed.enabled` | 启用分布式模式 | `true` | +| `replicaCount` | 分布式 Pod 数量 | `4` | +| `drivesPerNode` | 每个 Pod 的数据 PVC 数量 | 根据 `replicaCount` 推断 | +| `storageclass.name` | PVC 使用的 StorageClass | `local-path` | +| `storageclass.dataStorageSize` | 每个数据 PVC 的大小 | `256Mi` | +| `storageclass.logStorageSize` | 每个日志 PVC 的大小 | `256Mi` | +| `service.endpoint.port` | S3 API 端口 | `9000` | +| `service.console.port` | 控制台端口 | `9001` | + +建议显式设置存储大小;chart 默认值仅用于基本评估。 \ No newline at end of file diff --git a/content/zh/installation/cloud-native/helm-chart/meta.json b/content/zh/installation/cloud-native/helm-chart/meta.json new file mode 100644 index 000000000..c439f5511 --- /dev/null +++ b/content/zh/installation/cloud-native/helm-chart/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Helm Chart", + "pages": [ + "installation", + "mtls", + "cert-manager" + ] +} \ No newline at end of file diff --git a/content/zh/installation/cloud-native/helm-chart/mtls.md b/content/zh/installation/cloud-native/helm-chart/mtls.md new file mode 100644 index 000000000..4cf775328 --- /dev/null +++ b/content/zh/installation/cloud-native/helm-chart/mtls.md @@ -0,0 +1,66 @@ +--- +title: mTLS +description: 为 Helm chart 部署的 RustFS Pod 配置双向 TLS。 +--- + +该 chart 可以为 RustFS Pod 通信启用双向传输层安全性(mTLS)。启用后,RustFS 会要求客户端证书,为生成的对等节点 URL 使用 HTTPS,并将服务器、客户端和 CA 材料挂载到每个 Pod 中。 + +## 环境要求 + +mTLS 使用 cert-manager 的 `Issuer` 和 `Certificate` 资源。启用前请安装 cert-manager,并确认其 CRD 可用: + +```bash +kubectl get crd certificates.cert-manager.io issuers.cert-manager.io +``` + +## 1. 使用 chart 管理的 CA + +将以下设置添加到现有 values 文件: + +```yaml title="values.yaml" +mtls: + enabled: true +``` + +升级 release: + +```bash +helm upgrade rustfs ./helm/rustfs \ + --namespace rustfs \ + -f values.yaml +``` + +该 chart 会创建自签名根 CA、命名空间级 Issuer 以及服务器和客户端 Certificate。它会挂载生成的 Secret,并使用 `RUSTFS_SERVER_MTLS_ENABLE=1` 和 `RUSTFS_TLS_PATH=/opt/tls` 配置 RustFS。健康探针也会使用生成的客户端证书。 + +## 2. 使用现有 Issuer + +如需使用平台已管理的 Issuer 或 ClusterIssuer,请配置其引用: + +```yaml title="values.yaml" +mtls: + enabled: true + existingIssuerRef: + enabled: true + name: internal-ca + kind: ClusterIssuer + group: cert-manager.io +``` + +该 issuer 必须处于就绪状态,并能够在 `rustfs` 命名空间中签发服务器和客户端证书。对于命名空间级 issuer,请使用 `kind: Issuer`。 + +## 3. 验证 mTLS + +```bash +kubectl -n rustfs get issuer,certificate,secret +kubectl -n rustfs describe certificate rustfs-server-tls +kubectl -n rustfs describe certificate rustfs-client-tls +kubectl -n rustfs get pods +``` + +对于名为 `rustfs` 的 release,生成的证书 Secret 是 `rustfs-server-tls` 和 `rustfs-client-tls`。 + +:::warning[规划外部访问] + +mTLS 要求客户端出示受信任的证书。在现有部署上启用 mTLS 前,请验证 Ingress 控制器或其他外部客户端如何提供该证书。 + +::: \ No newline at end of file diff --git a/content/zh/installation/cloud-native/index.md b/content/zh/installation/cloud-native/index.md new file mode 100644 index 000000000..7b70c9f90 --- /dev/null +++ b/content/zh/installation/cloud-native/index.md @@ -0,0 +1,201 @@ +--- +title: "Kubernetes 安装(Helm)" +description: "使用官方 Helm chart 在 Kubernetes 上部署 RustFS:单机或分布式模式、存储容量规划、探针、生产环境加固和服务器池扩容。" +--- + +RustFS 提供官方 Helm chart,可部署单节点实例(一个包含一个 PVC 的 `Deployment`)或分布式集群(一个包含多个 Pod 和 PVC 的 `StatefulSet`)。本指南介绍如何安装 chart、选择部署模式、正确规划存储容量,以及 chart 提供的生产环境选项。 + +**前提条件** + +- Kubernetes 集群和 `kubectl` 访问权限 +- Helm 3 +- RustFS 镜像版本 `>= 1.0.0-alpha.69`(chart 要求) +- 具有可用预配器的 StorageClass。chart 默认为 [`local-path`](https://github.com/rancher/local-path-provisioner);设置 `storageclass.name` 可使用自己的 StorageClass +- 使用本指南中的服务器池命令前,管理主机上已安装 [`rc`](/operations/rc) + +该 chart 位于 RustFS 源代码仓库的 `helm/rustfs` 下: + +```bash +git clone https://github.com/rustfs/rustfs.git +cd rustfs/helm/rustfs +``` + +## 1. 快速安装 + +安装到专用命名空间,并设置自己的凭证和实际的数据容量: + +```bash +helm install rustfs . \ + --namespace rustfs --create-namespace \ + --set secret.rustfs.access_key= \ + --set secret.rustfs.secret_key= \ + --set storageclass.dataStorageSize=100Gi \ + --set storageclass.logStorageSize=1Gi +``` + +:::note[chart 拒绝默认凭证] + +除非满足以下任一条件,否则默认情况下渲染会失败: + +1. `secret.existingSecret` 指定你控制的 Kubernetes Secret,或 +2. `secret.rustfs.access_key` 和 `secret.rustfs.secret_key` **都**设置为非空、非默认值,或 +3. 设置 `secret.allowInsecureDefaults: true`(仅限本地开发)。 + +这可以避免意外使用众所周知的默认 `rustfsadmin`/`rustfsadmin` 凭证进行部署。仅设置两个密钥中的一个也会被拒绝,因此 chart 不会静默地为缺失密钥回退到默认值。 + +::: + +观察 Pod 启动: + +```bash +kubectl -n rustfs get pods -w +``` + +```text +NAME READY STATUS RESTARTS AGE +rustfs-0 1/1 Running 0 2m27s +rustfs-1 1/1 Running 0 2m27s +rustfs-2 1/1 Running 0 2m27s +rustfs-3 1/1 Running 0 2m27s +``` + +## 2. 选择部署模式 + +该 chart 支持通过 `mode` 值选择两种模式: + +| 模式 | 值 | 工作负载 | 布局 | +| --- | --- | --- | --- | +| 分布式(**默认**) | `mode.distributed.enabled=true` | StatefulSet | `replicaCount: 4` 个 Pod,每个 Pod 4 个数据 PVC(共 16 个驱动器);或设置 `replicaCount: 16`,使用 16 个 Pod,每个 Pod 1 个数据 PVC | +| 单机 | `mode.standalone.enabled=true`、`mode.distributed.enabled=false` | Deployment | 1 个 Pod、1 个数据 PVC(单节点单磁盘) | + +- **单机模式**对应单节点单磁盘:节点之间不提供纠删码冗余。适用于开发、测试或底层存储自身提供持久性的小型部署。它可以通过 `mode.standalone.existingClaim.dataClaim` / `mode.standalone.existingClaim.logsClaim` 复用现有 PVC。 +- **分布式模式**的行为类似[多节点多磁盘](../linux/multiple-node-multiple-disk.md):对象通过纠删码分布到各 Pod 和 PVC。`replicaCount` 必须为 `4`(每个 Pod 获得 4 个 PVC)或 `16`(每个 Pod 获得 1 个 PVC);请根据集群能够将 Pod 分布到多少个节点来选择。 + +```bash +# Standalone mode +helm install rustfs . -n rustfs --create-namespace \ + --set mode.standalone.enabled=true \ + --set mode.distributed.enabled=false \ + --set secret.rustfs.access_key= \ + --set secret.rustfs.secret_key= +``` + +## 3. 存储容量规划 + +PVC 大小来自 `storageclass` 区块: + +```yaml title="values-prod.yaml" +storageclass: + name: local-path # your StorageClass + dataStorageSize: 256Mi # per data PVC + logStorageSize: 256Mi # per logs PVC +``` + +:::warning[默认 PVC 大小为 256Mi,请更改] + +chart 的数据卷和日志卷默认大小为 **256Mi**,仅足以验证 chart 是否可用。对于任何实际工作负载,请在安装时设置 `storageclass.dataStorageSize`(例如 `1Ti`)和 `storageclass.logStorageSize`(例如 `1Gi`)。在分布式模式下,数据大小应用于**每个**数据 PVC(默认 16 个 PVC)。 + +::: + +将 `config.rustfs.obs_log_directory` 设置为 `""` 可完全禁用日志 PVC 和挂载。自定义 PVC 注解位于 `storageclass.pvcAnnotations.data` / `storageclass.pvcAnnotations.logs` 下。 + +## 4. 健康探针 + +chart 默认在 S3 端口(9000)上设置 HTTP 探针,与服务器的健康检查端点一致: + +- **存活探针**:`GET /health`(`livenessProbe.httpGet.path`),初始延迟 30s,周期 5s +- **就绪探针**:`GET /health/ready`(`readinessProbe.httpGet.path`),初始延迟 10s,周期 5s + +只有当 `/health/ready` 返回 `200` 后,Pod 才会添加到 Service 端点。在分布式模式下,这要求满足存储仲裁。可通过 `livenessProbe.*` 和 `readinessProbe.*` 值调整阈值和时间。 + +## 5. 生产环境加固 + +### Pod Disruption Budget + +默认禁用。启用后,自愿中断(节点排空、集群升级)一次不会导致超过一个 Pod 停止: + +```bash +--set pdb.create=true # pdb.maxUnavailable defaults to 1 +``` + +### 反亲和性和拓扑分布 + +`affinity.podAntiAffinity.enabled` 默认为 `true`,并使用 `topologyKey: kubernetes.io/hostname` 将 Pod 分布到不同节点。对于可用区级分布,请启用 `topologySpreadConstraints.enabled`,并在 `topologySpreadConstraints.constraints` 下提供原始约束条目(应用于分布式 StatefulSet)。 + +### Pod 间 mTLS(cert-manager) + +设置 `mtls.enabled=true` 可加密 Pod 之间的流量;chart 会为 CA、服务器和客户端证书渲染 cert-manager `Issuer`/`Certificate` 资源。要使用已在运维的 issuer,请设置 `mtls.existingIssuerRef.enabled=true`,并提供其 `name`、`kind`(`Issuer` 或 `ClusterIssuer`)和 `group`。 + +### Ingress 和 Gateway API + +Ingress 默认启用(`ingress.enabled=true`),且 `ingress.className: nginx`;如果使用 Traefik 控制器,请将其设置为 `traefik`,chart 会为各控制器应用匹配的会话粘性注解。通过 `ingress.hosts[0].host` 设置域名(默认为 `example.rustfs.com`)。要使用 HTTPS,请启用 `ingress.tls.enabled`,并通过 `--set-file ingress.tls.crt=./tls.crt --set-file ingress.tls.key=./tls.key` 传入证书、指向现有 Secret(`ingress.tls.existingSecret`),或让 cert-manager 签发证书(`ingress.tls.certManager.enabled=true`)。 + +该 chart 还提供 alpha 阶段的 [Gateway API](https://gateway-api.sigs.k8s.io/) 支持(同时设置 `gatewayApi.enabled=true` 和 `ingress.enabled=false`,使用 Traefik gateway class),并渲染 `Gateway` 和 `HTTPRoute` 资源。 + +## 6. 访问 RustFS + +没有 ingress 时,对 Service 进行端口转发: + +```bash +kubectl -n rustfs port-forward svc/rustfs 9000:9000 9001:9001 +``` + +- S3 API:`http://localhost:9000` +- 控制台:`http://localhost:9001` + +使用安装时设置的访问密钥和秘密密钥登录控制台。启用 ingress 后,改用配置的主机(运行 `kubectl -n rustfs get ing` 检查)。Service 默认为 `ClusterIP`;可将 `service.type` 切换为 `NodePort`(S3 使用 `service.endpoint.nodePort: 32000`,控制台使用 `service.console.nodePort: 32001`)或 `LoadBalancer`。 + +## 7. 使用服务器池横向扩容 + +在分布式模式下,chart 可以运行多个**服务器池**,每个服务器池都是独立的 StatefulSet,其驱动器共同组成一个集群。这相当于在 chart 层添加[存储池扩容](../../operations/scaling/storage-pool-expansion.md)中所述的服务器池。 + +要扩展现有部署,请启用存储池,并将当前布局描述为存储池 0,再添加新容量: + +```yaml title="values-prod.yaml (pools)" +pools: + enabled: true + list: + - {} # pool 0: inherits top-level values and keeps the + # existing StatefulSet/pod/PVC names and data + - replicaCount: 4 # pool 1: new capacity (4 or 16) + storageclass: + dataStorageSize: 10Gi +``` + +然后使用 `helm upgrade` 应用。每个条目可以设置 `replicaCount`(4 或 16)和/或 `storageclass` 区块;省略的字段继承顶层值。其他存储池渲染为 `-pool` StatefulSet;所有存储池共享无头 Service、主 Service、配置和凭证。 + +:::warning[存储池仅可追加] + +列表索引决定 StatefulSet 名称,切勿删除条目或调整顺序。从列表中删除存储池前,请使用 `rc admin decommission` 将其停用。 + +::: + +根据 chart 文档,滚动更新期间会出现以下情况: + +- **崩溃/重启循环属于正常现象。** Pod 会不断重启,直到所有存储池的所有 Pod 都能解析。服务器拒绝在存在无法解析的对等节点时启动,因此集群收敛前可能出现几次崩溃循环。这不会造成损害。 +- **之后重新平衡。** 集群收敛后,运行 `rc admin rebalance start ` 将现有对象分布到新存储池。 +- PodDisruptionBudget 跨所有存储池生效:使用默认 `pdb.maxUnavailable: 1` 时,整个集群一次最多驱逐一个 Pod。 + +:::note + +`rc` 是 RustFS 命令行客户端。使用 `rc admin pool list`、`expand`、`rebalance` 和 `decommission` 完成 chart 所述的服务器池工作流。 + +::: + +## 8. 卸载 + +```bash +helm uninstall rustfs -n rustfs +``` + +:::note + +Helm 不会删除 StatefulSet volume claim template 创建的 PVC。如果确定要丢弃数据,请显式删除 PVC(`kubectl -n rustfs delete pvc -l app.kubernetes.io/name=rustfs`);否则以后使用相同 release 名称重新安装时会重新挂载这些 PVC。 + +::: + +## 后续步骤 + +- [存储池扩容](../../operations/scaling/storage-pool-expansion.md):服务器池扩容在集群层的工作方式 +- [Kubernetes 升级](../../operations/upgrade/kubernetes/index.md):升级由 Helm 和 Operator 管理的部署 +- [TLS 配置](../../integration/tls-configured.md):端到端 TLS 选项 \ No newline at end of file diff --git a/content/zh/installation/cloud-native/meta.json b/content/zh/installation/cloud-native/meta.json new file mode 100644 index 000000000..a72474510 --- /dev/null +++ b/content/zh/installation/cloud-native/meta.json @@ -0,0 +1,7 @@ +{ + "title": "云原生", + "pages": [ + "helm-chart", + "operator" + ] +} diff --git a/content/zh/installation/cloud-native/operator/index.md b/content/zh/installation/cloud-native/operator/index.md new file mode 100644 index 000000000..5b8bf927f --- /dev/null +++ b/content/zh/installation/cloud-native/operator/index.md @@ -0,0 +1,28 @@ +--- +title: 概述 +description: 了解 RustFS Operator 如何在 Kubernetes 上管理 RustFS 集群。 +--- + +**RustFS Operator** 将 Kubernetes Operator 模式应用于 RustFS 集群。你无需手动创建 StatefulSet、Service、PersistentVolumeClaim(PVC)和配置,只需将所需的存储集群声明为 Kubernetes 自定义资源。控制器会监视该资源,并持续协调运行中集群与声明状态,使二者保持一致。 + +Operator 会安装两个 Custom Resource Definition(CRD): + +- `Tenant`(`rustfs.com/v1alpha1`)表示一个 RustFS 集群。它定义存储池、凭证、调度、传输层安全性(TLS)和密钥管理服务(KMS)设置。 +- `PolicyBinding`(`sts.rustfs.com/v1alpha1`)在工作负载从 Operator Security Token Service(STS)请求临时凭证时,将 Kubernetes ServiceAccount 映射到 RustFS 策略。 + +一个 Operator 可以跨命名空间管理多个租户。每个租户都有独立的存储、凭证、S3 和控制台服务以及生命周期。Operator 为每个存储池创建一个 StatefulSet,因此你可以通过追加存储池来扩容,而无需重建集群。它还会报告 `Ready`、`Progressing` 或 `Degraded` 状况以及 Kubernetes Event,并公开用于集群监控的健康检查和指标端点。 + +同一套 API 同时适用于小型测试集群和分布式部署。敏感凭证和 KMS 材料保存在 Kubernetes Secret 中,纳入版本控制的 Tenant manifest 仅包含 Secret 引用。这让部署可重复执行,支持 GitOps 工作流,并可通过 Kubernetes 原生工具完成多租户管理、存储池扩容、TLS 和加密等日常操作。 + +## Operator 工作流 + +- [安装](./installation.md)介绍环境要求、Helm 安装、控制台访问和 TLS 配置。 +- [多租户](./tenant.md)为不同团队或工作负载创建相互隔离的 RustFS 集群。 +- [存储池扩容](./pool-expansion.md)通过向现有租户追加存储池来增加存储容量。 +- [KMS 集成](./kms.md)为加密数据配置本地或 HashiCorp Vault 密钥管理。 + +:::warning[预发布软件] + +RustFS Operator 目前是正在积极开发的 `v0.1.0` 预发布软件。请先在非生产集群中验证升级和租户变更。 + +::: \ No newline at end of file diff --git a/content/zh/installation/cloud-native/operator/installation.md b/content/zh/installation/cloud-native/operator/installation.md new file mode 100644 index 000000000..8be11bc6b --- /dev/null +++ b/content/zh/installation/cloud-native/operator/installation.md @@ -0,0 +1,119 @@ +--- +title: 安装 +description: 准备 Kubernetes、安装 RustFS Operator 并安全访问其控制台。 +--- + +本指南使用 Helm 安装 Operator、验证部署,并在本地或通过 HTTPS 公开 Operator 控制台。 + +## 环境要求 + +| 组件 | 要求 | +|-----------|-------------| +| Kubernetes | `v1.30` 或更高版本 | +| Helm | `v3.0` 或更高版本 | +| kubectl | 与 Kubernetes 集群兼容 | +| StorageClass | 为 Tenant 存储动态预配 PVC | + +你的账户必须能够创建 CRD、集群 RBAC、Deployment 和 Service。安装前确认目标集群: + +```bash +kubectl config current-context +kubectl get storageclass +``` + +## 1. 安装 Operator + +Helm chart 存储在 Operator 仓库中: + +```bash +git clone https://github.com/rustfs/operator.git +cd operator + +helm upgrade --install rustfs-operator deploy/rustfs-operator/ \ + --namespace rustfs-system \ + --create-namespace +``` + +通用设置应放在 values 文件中: + +```yaml title="values.yaml" +operator: + replicas: 1 + metrics: + enabled: true + tenantMonitor: + enabled: true + intervalSeconds: 300 +console: + enabled: true + service: + type: ClusterIP +``` + +使用 `-f values.yaml` 应用该文件。chart 会根据这些值生成 `OPERATOR_*` 变量;不要在 `operator.env` 中重复定义。 + +## 2. 验证安装 + +```bash +kubectl -n rustfs-system get pods,services +kubectl get crd tenants.rustfs.com +kubectl -n rustfs-system rollout status deployment/rustfs-operator +kubectl -n rustfs-system rollout status deployment/rustfs-operator-console +``` + +## 3. 访问 Operator 控制台 + +控制台监听端口 `9090`。生成短期登录 token: + +```bash +kubectl -n rustfs-system create token rustfs-operator-console --duration=24h +``` + +将控制台 Service 转发到工作站: + +```bash +kubectl -n rustfs-system port-forward \ + svc/rustfs-operator-console 19090:9090 +``` + +打开 `http://127.0.0.1:19090`,将 token 粘贴到登录表单中。当 release 名称或命名空间不同时,Helm 安装说明会输出准确的 ServiceAccount 和 Service 名称。 + +:::note[本地 HTTP 访问] + +如果浏览器无法通过 HTTP 保持登录,请仅为本地测试在 `console.env` 下设置 `CONSOLE_COOKIE_SECURE=false`。使用 HTTPS 时请保持安全 cookie 启用。 + +::: + +## 4. 配置控制台 TLS + +为控制台 UI 和 `/api/v1` 使用同一个 HTTPS 主机名。创建 TLS Secret,或让 cert-manager 创建,然后启用 Ingress: + +```yaml title="values.yaml" +console: + ingress: + enabled: true + className: nginx + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + hosts: + - host: console.example.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: console-tls + hosts: + - console.example.com +``` + +使用 values 文件升级 release: + +```bash +helm upgrade rustfs-operator deploy/rustfs-operator/ \ + --namespace rustfs-system \ + -f values.yaml +``` + +请根据环境替换 Ingress class、issuer 和主机名。如果未安装 cert-manager,请在升级前使用证书和私钥创建 `console-tls` Secret。 + +接下来,[创建 Tenant](./tenant.md)。 \ No newline at end of file diff --git a/content/zh/installation/cloud-native/operator/kms.md b/content/zh/installation/cloud-native/operator/kms.md new file mode 100644 index 000000000..4a47a448e --- /dev/null +++ b/content/zh/installation/cloud-native/operator/kms.md @@ -0,0 +1,89 @@ +--- +title: KMS 集成 +description: 通过 Operator 加密 API 为 RustFS Tenant 配置本地或 HashiCorp Vault 密钥管理。 +--- + +通过 `spec.encryption` 配置密钥管理服务(KMS)集成。不要将 `RUSTFS_KMS_*` 变量添加到 `spec.env`;Operator 会根据结构化 Tenant 配置和 Secret 引用生成这些变量。 + +## 选择后端 + +仅对单服务器 Tenant 使用 `local`。对于每个 Tenant Pod 都能访问 HashiCorp Vault 的分布式部署,请使用 `vault`。 + +## 本地 KMS + +创建主密钥 Secret: + +```yaml title="local-kms-secret.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: rustfs-local-kms + namespace: storage-a +type: Opaque +stringData: + local-master-key: "replace-with-a-random-master-key" +``` + +将加密区块添加到现有 Tenant manifest: + +```yaml title="tenant.yaml" +spec: + encryption: + enabled: true + backend: local + local: + keyDirectory: /data/rustfs0/.kms-keys + masterKeySecretRef: + name: rustfs-local-kms + key: local-master-key + defaultKeyId: tenant-default +``` + +密钥目录必须位于已挂载的数据路径中,以便更换 Pod 后仍然保留。 + +## HashiCorp Vault KMS + +创建包含 Vault token 的 Secret: + +```yaml title="vault-kms-secret.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: rustfs-kms + namespace: storage-a +type: Opaque +stringData: + vault-token: "replace-with-vault-token" +``` + +将 Vault 配置添加到现有 Tenant manifest: + +```yaml title="tenant.yaml" +spec: + encryption: + enabled: true + backend: vault + vault: + endpoint: https://vault.example.com:8200 + kmsSecret: + name: rustfs-kms + defaultKeyId: tenant-default +``` + +每个 Tenant Pod 都必须能够解析并连接 Vault 端点,且信任其证书。 + +## 应用配置 + +```bash +kubectl apply -f local-kms-secret.yaml +kubectl apply -f tenant.yaml +kubectl -n storage-a describe tenant tenant-a +``` + +使用 Vault 时,请先应用 `vault-kms-secret.yaml`,再应用 `tenant.yaml`。更改加密设置会滚动更新受影响的 StatefulSet。 + +:::warning[保护加密密钥] + +存储生产数据前,请备份密钥材料并测试恢复流程。丢失本地主密钥或 Vault 密钥可能导致加密对象无法恢复。 + +::: \ No newline at end of file diff --git a/content/zh/installation/cloud-native/operator/meta.json b/content/zh/installation/cloud-native/operator/meta.json new file mode 100644 index 000000000..843952a8b --- /dev/null +++ b/content/zh/installation/cloud-native/operator/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Operator", + "pages": [ + "installation", + "tenant", + "pool-expansion", + "kms" + ] +} \ No newline at end of file diff --git a/content/zh/installation/cloud-native/operator/pool-expansion.md b/content/zh/installation/cloud-native/operator/pool-expansion.md new file mode 100644 index 000000000..f2c9f541d --- /dev/null +++ b/content/zh/installation/cloud-native/operator/pool-expansion.md @@ -0,0 +1,55 @@ +--- +title: 存储池扩容 +description: 通过追加存储池增加 RustFS Tenant 的存储容量。 +--- + +Tenant 中的所有存储池共同组成一个 RustFS 集群。通过向 `spec.pools` 追加新存储池来增加容量;不要更改现有存储池的结构。 + +:::warning[现有存储池不可变] + +不要更改现有存储池的 `servers` 或 `persistence.volumesPerServer`。Operator 会为每个存储池创建不可变的 StatefulSet。 + +::: + +## 1. 检查 Tenant + +```bash +kubectl -n storage-a get tenant tenant-a +kubectl -n storage-a get pods,pvc -l rustfs.tenant=tenant-a +``` + +确认 Tenant 处于 `Ready` 状态,并且集群具有足够的计算和存储容量。 + +## 2. 添加存储池 + +将以下条目追加到 `tenant.yaml` 中现有的 `spec.pools` 列表。保持所有现有条目不变。 + +```yaml title="tenant.yaml" +- name: pool-1 + servers: 2 + persistence: + volumesPerServer: 2 + volumeClaimTemplate: + storageClassName: standard + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi +``` + +该存储池会创建四个 PVC:两台服务器乘以每台服务器两个卷。应用完整的 Tenant manifest: + +```bash +kubectl apply -f tenant.yaml +``` + +## 3. 观察扩容过程 + +```bash +kubectl -n storage-a get tenant tenant-a -w +kubectl -n storage-a get pods,pvc \ + -l rustfs.pool=pool-1 +``` + +等待 Tenant 恢复到 `Ready` 状态后,再进行其他拓扑变更。扩展现有 PVC 容量属于独立的 Kubernetes 存储操作,并依赖 StorageClass。 \ No newline at end of file diff --git a/content/zh/installation/cloud-native/operator/tenant.md b/content/zh/installation/cloud-native/operator/tenant.md new file mode 100644 index 000000000..ac4f0f5e7 --- /dev/null +++ b/content/zh/installation/cloud-native/operator/tenant.md @@ -0,0 +1,74 @@ +--- +title: 多租户 +description: 创建相互隔离的 RustFS Tenant,并访问其 S3 API 和控制台服务。 +--- + +一个 `Tenant` 表示一个独立的 RustFS 集群。请为每个团队或工作负载使用单独的命名空间、凭证 Secret 和 Tenant 资源。 + +## 1. 创建命名空间和凭证 + +直接创建 Secret,避免在 manifest 中存储凭证: + +```bash +kubectl create namespace storage-a +kubectl -n storage-a create secret generic rustfs-tenant-creds \ + --from-literal=accesskey='' \ + --from-literal=secretkey='' +``` + +## 2. 定义 Tenant + +这个开发环境示例会创建一个 RustFS Pod 和一个 `10Gi` PVC。请将 `standard` 替换为集群中的 StorageClass。 + +```yaml title="tenant.yaml" +apiVersion: rustfs.com/v1alpha1 +kind: Tenant +metadata: + name: tenant-a + namespace: storage-a +spec: + image: rustfs/rustfs:1.0.0-beta.10 + credsSecret: + name: rustfs-tenant-creds + pools: + - name: pool-0 + servers: 1 + persistence: + volumesPerServer: 1 + volumeClaimTemplate: + storageClassName: standard + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +``` + +## 3. 应用并验证 + +```bash +kubectl apply -f tenant.yaml +kubectl -n storage-a get tenant,pods,pvc,svc +kubectl -n storage-a describe tenant tenant-a +``` + +## 4. 访问 RustFS + +```bash +kubectl -n storage-a port-forward svc/tenant-a-io 9000:9000 +kubectl -n storage-a port-forward svc/tenant-a-console 9001:9001 +``` + +请在不同终端中运行这些命令。将 `http://localhost:9000` 用作 S3 端点,并打开 `http://localhost:9001` 访问 Tenant 控制台。 + +如需添加其他 Tenant,请使用不同的命名空间、Secret 和 Tenant 名称重复上述过程。使用以下命令列出所有受管 Tenant: + +```bash +kubectl get tenants --all-namespaces +``` + +:::warning[生产拓扑] + +单服务器示例仅用于评估。生产 Tenant 需要分布式存储池布局、资源请求、调度约束和不可变镜像引用。 + +::: \ No newline at end of file diff --git a/content/zh/installation/container/docker.md b/content/zh/installation/container/docker.md new file mode 100644 index 000000000..be88b5171 --- /dev/null +++ b/content/zh/installation/container/docker.md @@ -0,0 +1,61 @@ +--- +title: "Docker" +description: "使用 Docker 和持久化容器存储运行单节点 RustFS 实例。" +--- + +使用官方 RustFS 镜像启动具有持久化存储的单节点实例。你需要可用的 Docker Engine,并拥有运行容器的权限。 + +## 1. 拉取镜像 + +```bash +docker pull rustfs/rustfs:latest +``` + +## 2. 创建持久化存储 + +创建命名卷,以便替换容器后对象数据仍然可用: + +```bash +docker volume create rustfs-data +``` + +## 3. 启动 RustFS + +运行容器前,请替换凭证占位符: + +```bash +docker run -d \ + --name rustfs \ + --restart unless-stopped \ + -p 9000:9000 \ + -p 9001:9001 \ + -v rustfs-data:/data \ + -e RUSTFS_ACCESS_KEY="" \ + -e RUSTFS_SECRET_KEY="" \ + -e RUSTFS_CONSOLE_ENABLE=true \ + rustfs/rustfs:latest \ + /data +``` + +:::warning[创建容器时设置凭证] + +在将 RustFS 接入网络前,请设置唯一的 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY` 环境变量。任一凭证都不要使用众所周知的 `rustfsadmin` 值。如果容器启动时未设置自定义凭证,请停止容器,并使用上面所示的两个 `-e` 选项重新创建;`rustfs-data` 卷会保持不变。 + +::: + +## 4. 验证部署 + +检查容器和 S3 API 健康检查端点: + +```bash +docker ps --filter name=rustfs +curl --fail http://localhost:9000/health +``` + +S3 API 位于 `http://localhost:9000`,控制台位于 `http://localhost:9001`。 + +## 后续步骤 + +- [RustFS 控制台](/administration/console) +- [配置 S3 客户端](../../developer/examples/aws-cli.md) +- [TLS 配置](../../integration/tls-configured.md) \ No newline at end of file diff --git a/content/zh/installation/container/index.mdx b/content/zh/installation/container/index.mdx new file mode 100644 index 000000000..93e34b83b --- /dev/null +++ b/content/zh/installation/container/index.mdx @@ -0,0 +1,302 @@ +--- +title: "使用 Docker 安装 RustFS" +description: "RustFS Docker 部署。" +--- + +RustFS 是高性能、兼容 S3 的开源分布式对象存储系统。在单节点单磁盘(SNSD)部署模式下,后端使用零纠删码,不提供额外数据冗余,适合本地测试和小规模场景。 +本文基于 RustFS 官方 Linux 二进制软件包,通过自定义 Dockerfile 将 RustFS 及其运行环境打包到容器中,并配置数据卷和环境变量以一键启动服务。 + +--- + +## 1. 前提条件 + +1. **主机要求** + + * 已安装 Docker(≥ 20.10),并能正常拉取镜像和运行容器 + * 本地路径 `/mnt/rustfs/data`(或自定义路径),用于挂载对象数据 + * 管理主机上已安装 [`rc`](/operations/rc),用于验证流程 +2. **网络和防火墙** + + * 确保主机端口 9000(S3 API)和 9001(控制台)可供外部访问,或与自定义端口一致 + +3. **目录权限** + + * RustFS 容器以 ID 为 `10001` 的非 root 用户 `rustfs` 运行。如果使用 docker 的 `-v` 将主机目录挂载到容器,请确保主机目录的所有者为 `10001`,否则会遇到权限拒绝错误。运行 `chown -R 10001:10001 /path/to/host_directory` 授予必要权限。 + +--- + +## 2. 拉取 RustFS 官方镜像 + +从 Docker Hub 拉取基于 Alpine 的官方镜像: + +```bash +docker pull rustfs/rustfs +``` + +--- + + + +## 3. 运行 RustFS 容器 + +使用上述镜像和配置,按以下方式运行 RustFS SNSD Docker: + +```bash + docker run -d \ + --name rustfs_local \ + -p 9000:9000 \ + -p 9001:9001 \ + -v /mnt/rustfs/data:/data \ + rustfs/rustfs:latest \ + /data +``` + +参数说明: + +* `-p 9000:9000`:将主机端口 9000 映射到容器 +* `-v /mnt/rustfs/data:/data`:挂载数据卷 +* `--name rustfs_local`:自定义容器名称 +* `-d`:在后台运行 + +--- + +### 完整配置示例 + +配置可以通过环境变量(推荐)或命令行参数传入,请选择一种方式;两者同时存在时,命令行参数优先。卷路径(`/data`)始终放在最后。 + + + + +```bash {7,8} +# Use a unique access key and a strong, random secret (e.g. openssl rand -base64 24) +docker run -d \ + --name rustfs \ + -p 9000:9000 \ + -p 9001:9001 \ + -v /mnt/rustfs/data:/data \ + -e RUSTFS_ACCESS_KEY="" \ + -e RUSTFS_SECRET_KEY="" \ + -e RUSTFS_ADDRESS=:9000 \ + -e RUSTFS_CONSOLE_ENABLE=true \ + rustfs/rustfs:latest \ + /data +``` + + + + +```bash {8,9} +# Use a unique access key and a strong, random secret (e.g. openssl rand -base64 24) +docker run -d \ + --name rustfs \ + -p 9000:9000 \ + -p 9001:9001 \ + -v /mnt/rustfs/data:/data \ + rustfs/rustfs:latest \ + --access-key "" \ + --secret-key "" \ + --address :9000 \ + --console-enable \ + /data +``` + + + + +### 常用配置组合 + +1. **基本配置**: + ```bash + docker run -d \ + -p 9000:9000 \ + -p 9001:9001 \ + -v /mnt/data:/data \ + rustfs/rustfs:latest \ + /data + ``` + +2. **启用控制台**: + ```bash + docker run -d \ + -p 9000:9000 \ + -p 9001:9001 \ + -v /mnt/data:/data \ + -e RUSTFS_CONSOLE_ENABLE=true \ + rustfs/rustfs:latest \ + --console-enable \ + /data + ``` + +3. **自定义身份验证密钥**: + ```bash + # Use a unique access key and a strong, random secret (e.g. openssl rand -base64 24) + docker run -d \ + -p 9000:9000 \ + -p 9001:9001 \ + -v /mnt/data:/data \ + -e RUSTFS_ACCESS_KEY="" \ + -e RUSTFS_SECRET_KEY="" \ + rustfs/rustfs:latest \ + --access-key "" \ + --secret-key "" \ + /data + ``` + +### 重要说明 + +1. 端口映射必须对应: + - 服务端口默认为 9000(`-p 9000:9000`) + +2. 数据卷必须持久化: + - `-v /host/path:/container/path` + +3. 环境变量和命令行参数可以混用,但命令行参数优先级更高 + +4. 如果[使用 TLS](../../integration/tls-configured.md),需要额外挂载证书路径: + + ```bash + -v /path/to/certs:/certs \ + -e RUSTFS_TLS_PATH=/certs \ + ``` + +### 使用 Docker Compose 安装 + +RustFS 官方提供 Docker Compose 安装方式。[`docker-compose.yml`](https://github.com/rustfs/rustfs/blob/main/docker-compose.yml) 文件包含 `grafana`、`prometheus`、`otel-collector` 和 `jaeger` 等多个服务,主要用于可观测性。如果要一起部署这些服务,请将 [RustFS 代码仓库](https://github.com/rustfs/rustfs)克隆到本地: + +```bash +git clone https://github.com/rustfs/rustfs.git +``` + +在根目录下运行命令: + +```bash +docker compose --profile observability up -d +``` + +提供必要的权限。需要使用初始化容器,通过 `depends_on` 关键字为 rustfs 授予正确的访问权限。以下示例将 `rustfs_perms` 服务添加到 `docker-compose.yml` 来处理权限。为了确保日志持久化且可访问,将主机日志目录映射到容器的 `/logs` 路径: + +```yaml title="docker-compose.yml" + services: + # grant the necessary permissions to RUSTFS volumes path + rustfs_perms: + image: alpine + user: root + volumes: + - /path/to/host_directory/volumes:/fix_path + command: chown -R 10001:10001 /fix_path + + rustfs: + image: rustfs/rustfs:latest + depends_on: + rustfs_perms: + condition: service_completed_successfully + volumes: + - /path/to_host_directory/volumes/data:/data + - /path/to_host_directory/volumes/logs:/logs + environment: + - RUSTFS_OBS_LOG_DIRECTORY=/logs + + # ... other configurations +``` + +启动后的容器如下: + +```text +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +c13c23fe3d9d rustfs/rustfs:latest "/entrypoint.sh rust…" 6 seconds ago Up 5 seconds (health: starting) 0.0.0.0:9000-9001->9000-9001/tcp, :::9000-9001->9000-9001/tcp rustfs-server +e3f4fc4a83a2 grafana/grafana:latest "/run.sh" 7 seconds ago Up 5 seconds 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp grafana +71ef1b8212cf prom/prometheus:latest "/bin/prometheus --c…" 7 seconds ago Up 5 seconds 0.0.0.0:9090->9090/tcp, :::9090->9090/tcp prometheus +e7db806b2d6f jaegertracing/all-in-one:latest "/go/bin/all-in-one-…" 7 seconds ago Up 5 seconds 4317-4318/tcp, 9411/tcp, 0.0.0.0:14250->14250/tcp, :::14250->14250/tcp, 14268/tcp, 0.0.0.0:16686->16686/tcp, :::16686->16686/tcp jaeger +1897830a2f1e otel/opentelemetry-collector-contrib:latest "/otelcol-contrib --…" 7 seconds ago Up 5 seconds 0.0.0.0:4317-4318->4317-4318/tcp, :::4317-4318->4317-4318/tcp, 0.0.0.0:8888-8889->8888-8889/tcp, :::8888-8889->8888-8889/tcp, 55679/tcp otel-collector +``` + +如果只想安装 RustFS,而不安装 Grafana、Prometheus 和其他可观测性服务,请仅启动 `rustfs` 服务(compose 文件将 collector 依赖项标记为可选): + +```bash +docker compose -f docker-compose.yml up -d rustfs +``` + +这样只会安装并启动 `rustfs-server` 服务,即 rustfs 容器: + +```text +docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +e07121ecdd39 rustfs/rustfs:latest "/entrypoint.sh rust…" 2 seconds ago Up 1 second (health: starting) 0.0.0.0:9000-9001->9000-9001/tcp, :::9000-9001->9000-9001/tcp rustfs-server +``` + +无论只启动 `rustfs-server` 还是同时启动可观测性服务,S3 API 都位于 `http://localhost:9000`,RustFS 控制台位于 `http://localhost:9001`。请在浏览器中打开控制台,使用上面配置的访问密钥和秘密密钥(`` / `` 占位符)登录。例如使用 `openssl rand -base64 24` 生成强密钥,绝不要将占位符值用于生产环境。 + +:::warning[立即设置容器凭证] + +在将 RustFS 接入网络前,请设置唯一的 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY` 环境变量。任一凭证都不要使用众所周知的 `rustfsadmin` 值。对于 `docker run`,使用 `-e` 传入这两个值。对于 Docker Compose,请在 `rustfs` 服务环境或用于变量替换的环境文件中定义这两个变量,然后使用 `docker compose up -d rustfs` 重新创建服务。 + +::: + +## 4. 验证和访问 + +1. **查看容器状态和日志:** + + ```bash + docker logs rustfs_local + ``` + + 日志应显示服务成功启动并监听端口 9000。 + +2. **测试 S3 API:** + + 使用 `rc` 验证 S3 API: + + ```bash + # Use a unique access key and a strong, random secret (e.g. openssl rand -base64 24) + rc alias set rustfs http://localhost:9000 + rc bucket create rustfs/my-bucket + rc bucket list rustfs/ + ``` + + 如果可以成功创建并列出存储桶,则部署有效。 + +## 5. 多节点 + +Docker 默认的桥接网络不支持多节点部署。使用 `--network host`,让每个容器可以直接与其他节点通信。 + +在**每个节点**上运行以下命令: + +```bash +# Use a unique access key and a strong, random secret (e.g. openssl rand -base64 24) +docker run -d \ + --name rustfs \ + --network host \ + -v /mnt/rustfs/data:/data \ + -e RUSTFS_ACCESS_KEY="" \ + -e RUSTFS_SECRET_KEY="" \ + -e RUSTFS_CONSOLE_ENABLE=true \ + -e RUSTFS_VOLUMES="http://node{1...4}:9000/data/rustfs{0...3}" \ + rustfs/rustfs:latest +``` + +在**每个**节点的 `/etc/hosts` 中添加条目: +```ini title="/etc/hosts" +192.168.1.1 node1 +192.168.1.2 node2 +192.168.1.3 node3 +192.168.1.4 node4 +``` + +## 6. 其他建议 + +1. 生产环境建议: +- 使用多节点部署架构 +- [启用 TLS 加密通信](../../integration/tls-configured.md) +- 配置日志轮转策略 +- 设置定期备份策略 + +2. 存储建议: +- 使用本地 SSD/NVMe 存储 +- 避免使用网络文件系统(NFS) +- 确保存储目录独占访问 + +--- + +## 总结 + +本文介绍使用 Docker 部署 RustFS 的最佳实践,从单节点单磁盘(SNSD)设置开始,再扩展到多节点部署选项。 \ No newline at end of file diff --git a/content/zh/installation/container/meta.json b/content/zh/installation/container/meta.json new file mode 100644 index 000000000..c6d8b8bba --- /dev/null +++ b/content/zh/installation/container/meta.json @@ -0,0 +1,7 @@ +{ + "title": "容器", + "pages": [ + "docker", + "podman" + ] +} \ No newline at end of file diff --git a/content/zh/installation/container/podman.md b/content/zh/installation/container/podman.md new file mode 100644 index 000000000..6d2214343 --- /dev/null +++ b/content/zh/installation/container/podman.md @@ -0,0 +1,60 @@ +--- +title: "Podman" +description: "使用 Podman 和持久化容器存储运行单节点 RustFS 实例。" +--- + +Podman 无需守护进程即可运行官方 RustFS Open Container Initiative(OCI)镜像。你需要可用的 Podman,并拥有创建容器的权限。 + +## 1. 拉取镜像 + +```bash +podman pull docker.io/rustfs/rustfs:latest +``` + +## 2. 创建持久化存储 + +创建命名卷,以便替换容器后对象数据仍然可用: + +```bash +podman volume create rustfs-data +``` + +## 3. 启动 RustFS + +运行容器前,请替换凭证占位符: + +```bash +podman run -d \ + --name rustfs \ + -p 9000:9000 \ + -p 9001:9001 \ + -v rustfs-data:/data \ + -e RUSTFS_ACCESS_KEY="" \ + -e RUSTFS_SECRET_KEY="" \ + -e RUSTFS_CONSOLE_ENABLE=true \ + docker.io/rustfs/rustfs:latest \ + /data +``` + +:::warning[创建容器时设置凭证] + +在将 RustFS 接入网络前,请设置唯一的 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY` 环境变量。任一凭证都不要使用众所周知的 `rustfsadmin` 值。如果容器启动时未设置自定义凭证,请停止容器,并使用上面所示的两个 `-e` 选项重新创建;`rustfs-data` 卷会保持不变。 + +::: + +## 4. 验证部署 + +检查容器和 S3 API 健康检查端点: + +```bash +podman ps --filter name=rustfs +curl --fail http://localhost:9000/health +``` + +S3 API 位于 `http://localhost:9000`,控制台位于 `http://localhost:9001`。 + +## 后续步骤 + +- [RustFS 控制台](/administration/console) +- [配置 S3 客户端](../../developer/examples/aws-cli.md) +- [TLS 配置](../../integration/tls-configured.md) \ No newline at end of file diff --git a/content/zh/installation/index.md b/content/zh/installation/index.md new file mode 100644 index 000000000..eece1c6be --- /dev/null +++ b/content/zh/installation/index.md @@ -0,0 +1,37 @@ +--- +title: "安装" +description: "根据本地试用、单节点或多节点生产环境、容器及 Kubernetes 场景选择合适的 RustFS 部署方式。" +--- + +RustFS 是使用 Rust 编写并采用 Apache 2.0 许可证发布的分布式对象存储系统。它可在 Linux、Windows、macOS、FreeBSD 和容器中运行,支持 x86、ARM、RISC-V 等 CPU 架构。 + +:::warning[立即更改默认凭证] + +安装后,在将 RustFS 接入网络前,请为 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY` 设置唯一值。任一凭证都不要使用众所周知的 `rustfsadmin` 值。 + +- 对于 Linux 二进制文件或 systemd 安装,请在 `/etc/default/rustfs` 中设置这两个值,然后重启 `rustfs` 服务。 +- 对于 Docker、Podman 或 Docker Compose,请在创建容器时将这两个值作为容器环境变量传入。如果现有容器启动时未设置这些值,请重新创建该容器。 + +::: + +## 选择部署方式 + +| 目标 | 推荐方式 | 指南 | +| - | - | - | +| 在本地计算机上试用 RustFS | 一键安装脚本或容器 | [Linux 快速入门](./linux/quick-start.md) · [容器](./container/index.mdx) | +| 单服务器生产环境 | SNSD(单磁盘)或 SNMD(多磁盘) | [在 Linux 上安装 RustFS](./linux/index.md) | +| 多服务器生产集群 | 完成生产检查清单后使用 MNMD | [多节点多磁盘](./linux/multiple-node-multiple-disk.md) · [检查清单](./requirement/checklists/index.md) | +| Kubernetes/云原生 | 容器编排部署 | [云原生](./cloud-native/index.md) | +| Windows 或 macOS 主机 | 原生安装 | [Windows](./windows/index.md) · [macOS](./macos/index.md) | + +## 部署模式对比 + +| 模式 | 节点 | 磁盘 | 容错能力 | 典型用途 | +| - | - | - | - | - | +| [SNSD](./linux/single-node-single-disk.md) | 1 | 1 | 无,需依赖备份 | 开发、测试和低密度非关键业务 | +| [SNMD](./linux/single-node-multiple-disk.md) | 1 | 多块 | 节点内最多容忍 M 块校验盘故障 | 单台服务器上的中等规模非关键业务 | +| [MNMD](./linux/multiple-node-multiple-disk.md) | 4+ | 每节点多块 | 通过跨服务器纠删码实现磁盘级和节点级容错 | 生产工作负载 | + +## 检查清单 + +部署任何生产环境前,请完成[安装前检查清单](./requirement/checklists/index.md),检查硬件、网络、软件和安全性,确保环境符合生产指导要求。 \ No newline at end of file diff --git a/content/zh/installation/linux/images/console.jpg b/content/zh/installation/linux/images/console.jpg new file mode 100644 index 000000000..2a6224d53 Binary files /dev/null and b/content/zh/installation/linux/images/console.jpg differ diff --git a/content/zh/installation/linux/index.md b/content/zh/installation/linux/index.md new file mode 100644 index 000000000..434d196f3 --- /dev/null +++ b/content/zh/installation/linux/index.md @@ -0,0 +1,34 @@ +--- +title: "在 Linux 上安装 RustFS" +description: "选择 SNSD、SNMD 或 MNMD Linux 部署模式,并在一台或多台服务器上安装 RustFS。" +--- + +本节介绍如何在 Linux 服务器上安装 RustFS。如需使用一条命令试用,请参阅[快速入门](./quick-start.md)。如需手动安装,请从以下三种部署模式中选择。三种模式使用相同的[前提条件和服务设置](./prerequisites-and-service.md),区别仅在于拓扑和卷配置。 + +:::warning[立即更改默认凭证] + +安装后,请在 `/etc/default/rustfs` 中为 `RUSTFS_ACCESS_KEY` 和 `RUSTFS_SECRET_KEY` 设置唯一值。任一凭证都不要使用众所周知的 `rustfsadmin` 值。更改文件后,运行 `sudo systemctl restart rustfs` 重启服务。 + +::: + +## 单节点单磁盘(SNSD) + +一台服务器、一块数据盘。这是最简单的模式,不提供冗余。磁盘故障会导致数据丢失,因此请依赖备份。适用于开发、测试和低密度的非关键业务。 + +→ [单节点单磁盘安装](./single-node-single-disk.md) + +## 单节点多磁盘(SNMD) + +一台服务器、多块数据盘。纠删码将数据分片到不同磁盘,因此节点可以容忍有限数量的磁盘故障,但整台服务器故障仍会导致数据丢失。适用于在单台服务器上运行的中等规模非关键业务。 + +→ [单节点多磁盘安装](./single-node-multiple-disk.md) + +## 多节点多磁盘(MNMD) + +四台或更多服务器,每台服务器配备一块或多块磁盘。纠删码跨服务器分布,可提供磁盘级和节点级容错能力以及水平扩展能力。这是生产工作负载应使用的模式。 + +→ [多节点多磁盘安装](./multiple-node-multiple-disk.md) + +## 投入生产前 + +部署到生产环境前,请完成[安装前检查清单](../requirement/checklists/index.md),检查硬件、网络、软件和安全性。如果不需要满足生产标准,可以跳过这些检查。 \ No newline at end of file diff --git a/content/zh/installation/linux/meta.json b/content/zh/installation/linux/meta.json new file mode 100644 index 000000000..6514d2cdb --- /dev/null +++ b/content/zh/installation/linux/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Linux", + "pages": [ + "[快速开始](/zh/installation/linux/quick-start)", + "[前提条件与服务配置](/zh/installation/linux/prerequisites-and-service)", + "[单节点单磁盘 (SNSD)](/zh/installation/linux/single-node-single-disk)", + "[单节点多磁盘 (SNMD)](/zh/installation/linux/single-node-multiple-disk)", + "[多节点多磁盘 (MNMD)](/zh/installation/linux/multiple-node-multiple-disk)" + ] +} diff --git a/content/zh/installation/linux/multiple-node-multiple-disk.md b/content/zh/installation/linux/multiple-node-multiple-disk.md new file mode 100644 index 000000000..ec2da226e --- /dev/null +++ b/content/zh/installation/linux/multiple-node-multiple-disk.md @@ -0,0 +1,122 @@ +--- +title: "RustFS 多节点多磁盘安装" +description: "在具有多块磁盘的多台服务器上安装 RustFS,数据将跨多台服务器存储在多块磁盘中。" +--- + +多节点多磁盘(MNMD)模式是生产工作负载的部署模式,可提供企业级性能、安全性和扩展能力。安全启动分布式对象存储集群至少需要 **4 台服务器**,每台服务器至少配备 1 块磁盘。 + +## 拓扑和规划 + +在以下架构中,请求通过负载均衡分发到服务器。采用默认的 12 + 4 纠删码布局时,每个对象会拆分为 12 个数据分片和 4 个校验分片,存储在不同服务器的不同磁盘上: + +- 任意单台服务器发生故障或维护都不会影响数据安全。 +- 最多 4 块磁盘损坏不会影响数据安全。 + +```mermaid +flowchart TD + LB([Load Balancing]) --> S1[Server Node1] & S2[Server Node2] & S3[Server Node3] & S4[Server Node4] + + S1 --> N1D1[(Disk1)] & N1D2[(Disk2)] & N1D3[(Disk3)] & N1D4[(Disk4)] + S2 --> N2D1[(Disk1)] & N2D2[(Disk2)] & N2D3[(Disk3)] & N2D4[(Disk4)] + S3 --> N3D1[(Disk1)] & N3D2[(Disk2)] & N3D3[(Disk3)] & N3D4[(Disk4)] + S4 --> N4D1[(Disk1)] & N4D2[(Disk2)] & N4D3[(Disk3)] & N4D4[(Disk4)] + + classDef lb fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#1e293b; + classDef server fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e293b; + classDef disk fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#1e293b; + class LB lb + class S1,S2,S3,S4 server + class N1D1,N1D2,N1D3,N1D4,N2D1,N2D2,N2D3,N2D4,N3D1,N3D2,N3D3,N3D4,N4D1,N4D2,N4D3,N4D4 disk +``` + +安装前,请审查[安装前检查清单](../requirement/checklists/index.md),确保所有项目都符合生产指导要求。 + +## 主机名 + +创建 RustFS 集群需要**相同格式且连续**的主机名。可通过两种方式实现连续主机名: + +**1. DNS 配置:** + +配置 DNS 解析服务器以确保名称连续。 + +**2. HOSTS 配置:** + +按如下方式修改 `/etc/hosts` 中的本地别名设置: + +```bash title="/etc/hosts" +vim /etc/hosts +127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 +::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 +192.168.1.1 node1 +192.168.1.2 node2 +192.168.1.3 node3 +192.168.1.4 node4 +``` + +## 前提条件和服务设置 + +在**每个节点**上完成[通用前提条件和服务设置](./prerequisites-and-service.md),包括操作系统、防火墙、时间同步、磁盘格式化、服务用户、二进制文件下载和 systemd 单元,然后继续执行以下步骤。请确保所有节点使用相同的监听端口并保持时钟同步。 + +## 配置环境变量 + +1. 在每个节点上创建相同的配置文件。`RUSTFS_VOLUMES` 使用大括号展开枚举所有节点和所有磁盘挂载点(本例为 4 个节点 × 4 块磁盘): + +```ini title="/etc/default/rustfs" +# Use a unique access key and a strong, random secret (e.g. openssl rand -base64 24) +RUSTFS_ACCESS_KEY= +RUSTFS_SECRET_KEY= +RUSTFS_VOLUMES="http://node{1...4}:9000/data/rustfs{0...3}" +RUSTFS_ADDRESS=":9000" +RUSTFS_CONSOLE_ENABLE=true +RUST_LOG=error +RUSTFS_OBS_LOG_DIRECTORY="/var/logs/rustfs/" +``` + +:::note + +所有节点上的访问密钥、秘密密钥和 `RUSTFS_VOLUMES` 值必须完全相同。主机名(`node1` – `node4`)必须与上面的 DNS 或 `/etc/hosts` 配置一致。 + +::: + +2. 在每个节点上创建存储和日志目录: + +```bash +sudo mkdir -p /data/rustfs{0..3} /var/logs/rustfs /opt/tls +sudo chmod -R 750 /data/rustfs* /var/logs/rustfs +``` + +## 启动服务并验证 + +1. 在每个节点上启动服务并启用开机自启动: + +```bash +sudo systemctl enable --now rustfs +``` + +2. 验证服务状态: + +```bash +systemctl status rustfs +``` + +3. 检查服务端口: + +```bash +netstat -ntpl +``` + +4. 查看日志文件: + +```bash +tail -f /var/logs/rustfs/rustfs*.log +``` + +5. 访问控制台:在浏览器中输入任一节点的 IP 地址(或负载均衡器地址)和控制台端口(默认 9001)。你将看到: + +![控制台](./images/console.jpg) + +## 后续步骤 + +- 在集群前部署负载均衡器,请参阅 [Nginx 集成指南](/developer/integration/reverse-proxy/nginx)。 +- 为生产流量启用 TLS,请参阅 [TLS 配置](../../integration/tls-configured.md)。 +- 扩容前请查看[存储池扩容](../../operations/scaling/storage-pool-expansion.md)。 \ No newline at end of file diff --git a/content/zh/installation/linux/prerequisites-and-service.md b/content/zh/installation/linux/prerequisites-and-service.md new file mode 100644 index 000000000..366a60609 --- /dev/null +++ b/content/zh/installation/linux/prerequisites-and-service.md @@ -0,0 +1,231 @@ +--- +title: "Linux 前提条件和服务设置" +description: "所有 RustFS Linux 部署模式共用的前提条件、磁盘准备、二进制文件安装和 systemd 服务设置。" +--- + +本页包含三种 Linux 部署模式共用的前提条件和服务设置步骤:[SNSD](./single-node-single-disk.md)、[SNMD](./single-node-multiple-disk.md) 和 [MNMD](./multiple-node-multiple-disk.md)。请先完成这些步骤,然后返回所选模式的页面配置环境文件并启动服务。 + +## 操作系统版本 + +建议使用 Linux 内核 4.x 或更高版本;5.x/6.x 版本可获得更好的 I/O 吞吐量和网络性能。Ubuntu 22.04 和 RHEL 8.x 都适合安装 RustFS。 + +## 防火墙 + +Linux 系统默认启用防火墙。使用以下命令检查防火墙状态: + +```bash +systemctl status firewalld +``` + +如果防火墙状态为 "active",可以禁用防火墙: + +```bash +systemctl stop firewalld +systemctl disable firewalld +``` + +也可以允许 RustFS S3 端口(9000)和控制台端口(9001): + +```bash +firewall-cmd --zone=public --add-port=9000/tcp --permanent +firewall-cmd --zone=public --add-port=9001/tcp --permanent +firewall-cmd --reload +``` + +同一部署中的所有 RustFS 服务器**必须**使用相同的监听端口。如果使用端口 9000,其他所有服务器也必须使用端口 9000。 + +## 内存要求 + +测试环境中 RustFS 至少需要 2 GB 内存;生产环境至少需要 128 GB 内存。 + +## 时间同步 + +多节点一致性需要时间服务器保持时钟一致,否则服务可能无法启动。可使用 `ntp`、`timedatectl` 或 `timesyncd` 等工具。 + +使用以下命令检查同步状态: + +```bash +timedatectl status +``` + +如果状态为 "synchronized",则时间同步工作正常。 + +## 容量规划 + +规划对象存储容量时,建议考虑: + +- 初始数据量:计划一次迁移或存储多少数据?(例如 500 TB) +- 数据增长量:每日/每周/每月的数据增长容量 +- 规划周期:本次硬件规划应覆盖多长时间?(建议:3 年) +- 公司的硬件迭代和更新周期。 + +部署前请查看 [EC 配置](../requirement/ec-configuration.md),计算可用容量、了解自动校验默认值,并验证任何显式校验数或纠删集宽度。 + +## 磁盘规划 + +由于 NFS 在高 I/O 下会产生虚假写入和锁问题,**禁止使用 NFS** 作为 RustFS 的底层存储介质。强烈建议使用 **JBOD(Just a Bunch of Disks)**模式:将物理磁盘直接、独立地公开给操作系统,并由 RustFS 软件层处理数据冗余和保护。 + +原因如下: + +- **性能更好:** RustFS 纠删码引擎经过高度优化,可并发读写多块磁盘,吞吐量高于硬件 RAID 控制器。硬件 RAID 会成为性能瓶颈。 +- **成本更低:** 无需昂贵的 RAID 卡,降低硬件采购成本。 +- **管理更简单:** RustFS 统一管理磁盘,简化存储层运维。 +- **故障恢复更快:** RustFS 修复过程比传统 RAID 重建更快,对集群性能的影响也更小。 + +为了获得更高性能和吞吐量,建议使用 NVMe SSD 作为存储介质。 + +## 文件系统选择 + +RustFS 强烈建议使用 XFS 文件系统格式化所有存储磁盘。RustFS 的开发和测试基于 XFS,可确保最佳性能和稳定性。请避免使用 ext4、BTRFS 或 ZFS 等其他文件系统,因为它们可能导致性能下降或不可预测的问题。 + +XFS 适合 RustFS 工作负载,原因有三: + +- **高并发 I/O:** XFS 专为高性能和扩展性而设计。其内部日志和数据结构(例如 B+ 树)可高效处理大量并行读写请求,与 RustFS 对大型对象进行分片并在纠删集中的多块磁盘上并行读写的方式相匹配。 +- **海量文件和大型文件:** XFS 是支持超大文件(最大 8 EB)的 64 位文件系统。即使单个目录包含数百万个文件,其元数据管理仍保持高效;这一点很重要,因为 RustFS 将每个对象(或对象版本)存储为独立文件。 +- **空间预留:** XFS 提供高效的 `fallocate` API。RustFS 使用它在写入对象前预留连续磁盘空间,避免写入期间动态扩展和更新元数据的开销,并尽量减少文件碎片。 + +为了更好地发现磁盘,建议在格式化 XFS 文件系统时使用 **Label** 标签。 + +首先检查磁盘布局: + +```bash +sudo lsblk + +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT +sda 8:0 0 465.7G 0 disk +├─sda1 8:1 0 512M 0 part /boot/efi +└─sda2 8:2 0 465.2G 0 part / +nvme0n1 8:16 0 3.7T 0 disk <-- if this is our format new disk +nvme1n1 8:32 0 3.7T 0 disk <-- if this is our format new disk +nvme2n1 8:48 0 3.7T 0 disk +``` + +格式化每块数据盘: + +```bash +sudo mkfs.xfs -i size=512 -n ftype=1 -L RUSTFS0 /dev/sdb +``` + +格式化选项: + +- `-L