INTEGRITY Dokumentace

Připojení bucketů

Připojte buckety objektového úložiště kompatibilního s S3 jako cesty v lokálním souborovém systému. K objektovému úložišti přistupujte pomocí standardních souborových operací. U Cloudflare R2 v produkčním prostředí můžete bucket připojit také podle názvu vazby R2 workeru, takže přihlašovací údaje zůstanou uvnitř runtime workeru.

Produkční předpoklady pro mounty R2 bindingu

Chcete-li v produkci připojit R2 bucket bez předávání přihlašovacích údajů do kontejneru, přidejte vazbu R2 a exportujte ContainerProxy z entrypointu vašeho Workeru.

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "r2_buckets": [
    {
      "binding": "MY_BUCKET",
      "bucket_name": "my-r2-bucket"
    }
  ]
}
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-r2-bucket"
import { ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };
import { ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };

Když vynecháte endpoint, první argument metody mountBucket() musí být název vazby R2 ve Workeru, například MY_BUCKET.

Kdy připojovat buckety

Buckety kompatibilní s S3 připojte, když potřebujete:

Připojení bucketu R2

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "data-processor");

// Mount R2 bucket by Worker binding name
await sandbox.mountBucket("MY_BUCKET", "/data");

// Access bucket with standard filesystem operations
await sandbox.exec("ls", { args: ["/data"] });
await sandbox.writeFile("/data/results.json", JSON.stringify(results));

// Use from Python
await sandbox.exec("python", {
	args: [
		"-c",
		`
import pandas as pd
df = pd.read_csv('/data/input.csv')
df.describe().to_csv('/data/summary.csv')
`,
	],
});
import { getSandbox } from '@cloudflare/sandbox';

const sandbox = getSandbox(env.Sandbox, 'data-processor');

// Mount R2 bucket by Worker binding name
await sandbox.mountBucket('MY_BUCKET', '/data');

// Access bucket with standard filesystem operations
await sandbox.exec('ls', { args: ['/data'] });
await sandbox.writeFile('/data/results.json', JSON.stringify(results));

// Use from Python
await sandbox.exec('python', { args: ['-c', `
import pandas as pd
df = pd.read_csv('/data/input.csv')
df.describe().to_csv('/data/summary.csv')
`] });

V tomto příkladu MY_BUCKET je název bindingu z wrangler.toml. Nemusí se shodovat s názvem bucketu v dashboardu, i když mnoho projektů používá shodné názvy.

Přihlašovací údaje

Mounty R2 bindingu nevyžadují přihlašovací údaje. Mounty vzdálených endpointů zůstávají podporované pro Cloudflare R2 i další poskytovatele kompatibilní s S3, přičemž tyto postupy mohou stále využívat automatickou detekci přihlašovacích údajů nebo explicitní přihlašovací údaje.

Automatická detekce

Když zahrnete endpoint, nastavte přihlašovací údaje jako tajné klíče Workeru a SDK je automaticky rozpozná:

npx wrangler secret put R2_ACCESS_KEY_ID
npx wrangler secret put R2_SECRET_ACCESS_KEY
// Credentials automatically detected from environment for remote endpoint mounts
await sandbox.mountBucket("my-r2-bucket", "/data", {
	endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com",
});
// Credentials automatically detected from environment for remote endpoint mounts
await sandbox.mountBucket('my-r2-bucket', '/data', {
	endpoint: 'https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com'
});

Explicitní přihlašovací údaje

V případě potřeby předejte přihlašovací údaje přímo:

await sandbox.mountBucket("my-r2-bucket", "/data", {
	endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com",
	credentials: {
		accessKeyId: env.R2_ACCESS_KEY_ID,
		secretAccessKey: env.R2_SECRET_ACCESS_KEY,
	},
});
await sandbox.mountBucket('my-r2-bucket', '/data', {
	endpoint: 'https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com',
	credentials: {
		accessKeyId: env.R2_ACCESS_KEY_ID,
		secretAccessKey: env.R2_SECRET_ACCESS_KEY
	}
});

Proxy pro přihlašovací údaje

Pokud připojíte úložiště s explicitně zadanými přihlašovacími údaji, s3fs tyto údaje zapíše do souboru s heslem na disku kontejneru. Napadený proces kontejneru pak může tyto údaje přečíst a odcizit, nebo je použít k přístupu do úložiště mimo zamýšlený rozsah bucketu.

Nastavte credentialProxy: true aby přihlašovací údaje vůbec nebyly v kontejneru. Durable Object místo předávání skutečných přihlašovacích údajů do kontejneru zachytává veškeré odchozí požadavky S3 na síťové vrstvě, znovu je podepíše skutečnými přihlašovacími údaji a přeposílá je dál. Kontejner tak vždy obsahuje jen fiktivní přihlašovací údaje, které jsou mimo proxy k ničemu.

To funguje s AWS SigV4 ↗ podepisování pro endpointy kompatibilní s S3 (včetně R2) a podepisování HMAC pro Google Cloud Storage. Doporučujeme nastavit credentialProxy: true pro všechna připojení koncových bodů. Ve výchozím nastavení má tato možnost hodnotu false kvůli zpětné kompatibilitě a v budoucí verzi Sandbox SDK se stane výchozí volbou.

await sandbox.mountBucket("my-bucket", "/data", {
	endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com",
	provider: "r2",
	credentials: {
		accessKeyId: env.R2_ACCESS_KEY_ID,
		secretAccessKey: env.R2_SECRET_ACCESS_KEY,
	},
	credentialProxy: true,
});
await sandbox.mountBucket('my-bucket', '/data', {
	endpoint: 'https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com',
	provider: 'r2',
	credentials: {
		accessKeyId: env.R2_ACCESS_KEY_ID,
		secretAccessKey: env.R2_SECRET_ACCESS_KEY
	},
	credentialProxy: true
});

Připojení podadresářů bucketu

Konkrétní podadresář v bucketu připojte pomocí prefix volba. V bodě připojení je viditelný pouze obsah pod tímto prefixem:

// Mount only the /uploads/images/ subdirectory
await sandbox.mountBucket("MY_BUCKET", "/images", {
	prefix: "/uploads/images/",
});

// Files appear at mount point without the prefix
// Bound bucket: my-r2-bucket/uploads/images/photo.jpg
// Mounted path: /images/photo.jpg
await sandbox.exec("ls", { args: ["/images"] });

// Write to subdirectory
await sandbox.writeFile("/images/photo.jpg", imageData);
// Creates my-r2-bucket/uploads/images/photo.jpg

// Mount different prefixes to different paths
await sandbox.mountBucket("MY_BUCKET", "/training-data", {
	prefix: "/ml/training/",
});

await sandbox.mountBucket("MY_BUCKET", "/test-data", {
	prefix: "/ml/testing/",
});
// Mount only the /uploads/images/ subdirectory
await sandbox.mountBucket('MY_BUCKET', '/images', {
	prefix: '/uploads/images/'
});

// Files appear at mount point without the prefix
// Bound bucket: my-r2-bucket/uploads/images/photo.jpg
// Mounted path: /images/photo.jpg
await sandbox.exec('ls', { args: ['/images'] });

// Write to subdirectory
await sandbox.writeFile('/images/photo.jpg', imageData);
// Creates my-r2-bucket/uploads/images/photo.jpg

// Mount different prefixes to different paths
await sandbox.mountBucket('MY_BUCKET', '/training-data', {
	prefix: '/ml/training/'
});

await sandbox.mountBucket('MY_BUCKET', '/test-data', {
	prefix: '/ml/testing/'
});

Mounty jen pro čtení

Chraňte data mountováním bucketů v režimu jen pro čtení:

await sandbox.mountBucket("MY_BUCKET", "/data", {
	readOnly: true,
});

// Reads work
await sandbox.exec("cat", { args: ["/data/dataset.csv"] });

// Writes fail
await sandbox.writeFile("/data/new-file.txt", "data"); // Error: Read-only filesystem
await sandbox.mountBucket('MY_BUCKET', '/data', {
	readOnly: true
});

// Reads work
await sandbox.exec('cat', { args: ['/data/dataset.csv'] });

// Writes fail
await sandbox.writeFile('/data/new-file.txt', 'data');  // Error: Read-only filesystem

Lokální vývoj

Během lokálního vývoje můžete také připojit R2 buckety pomocí wrangler dev předáním localBucket volba. Produkční připojení vazby R2 a lokální localBucket připojení se oběma vyhýbají explicitním přihlašovacím údajům, ale jde o odlišné způsoby provádění. Produkce používá zachytávání odchozího provozu bez přihlašovacích údajů a překrývá cílovou cestu. Lokální vývoj používá pravidelnou synchronizaci s vazbou R2.

await sandbox.mountBucket("MY_BUCKET", "/data", {
	localBucket: true,
});

// Access files using standard operations
await sandbox.exec("ls", { args: ["/data"] });
await sandbox.writeFile("/data/results.json", JSON.stringify(results));
await sandbox.mountBucket('MY_BUCKET', '/data', {
	localBucket: true
});

// Access files using standard operations
await sandbox.exec('ls', { args: ['/data'] });
await sandbox.writeFile('/data/results.json', JSON.stringify(results));

readOnly a prefix volby fungují stejně i v lokálním režimu:

// Read-only local mount
await sandbox.mountBucket("MY_BUCKET", "/data", {
	localBucket: true,
	readOnly: true,
});

// Mount a subdirectory
await sandbox.mountBucket("MY_BUCKET", "/images", {
	localBucket: true,
	prefix: "/uploads/images/",
});
// Read-only local mount
await sandbox.mountBucket('MY_BUCKET', '/data', {
	localBucket: true,
	readOnly: true
});

// Mount a subdirectory
await sandbox.mountBucket('MY_BUCKET', '/images', {
	localBucket: true,
	prefix: '/uploads/images/'
});

Aspekty místního vývoje

Při lokálním vývoji se soubory synchronizují mezi R2 a kontejnerem pomocí periodického synchronizačního procesu, nikoli přímým připojením souborového systému. Mějte na paměti následující:

Odpojení bucketů

// Mount for processing
await sandbox.mountBucket("MY_BUCKET", "/data");

// Do work
await sandbox.exec("python process_data.py");

// Clean up
await sandbox.unmountBucket("/data");
// Mount for processing
await sandbox.mountBucket('MY_BUCKET', '/data');

// Do work
await sandbox.exec('python process_data.py');

// Clean up
await sandbox.unmountBucket('/data');

Ostatní poskytovatelé

SDK podporuje jakékoli objektové úložiště kompatibilní s S3. Zde jsou příklady pro běžné poskytovatele:

Amazon S3

await sandbox.mountBucket("my-s3-bucket", "/data", {
	endpoint: "https://s3.us-west-2.amazonaws.com",
	credentials: {
		accessKeyId: env.AWS_ACCESS_KEY_ID,
		secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
	},
});
await sandbox.mountBucket('my-s3-bucket', '/data', {
	endpoint: 'https://s3.us-west-2.amazonaws.com',
	credentials: {
		accessKeyId: env.AWS_ACCESS_KEY_ID,
		secretAccessKey: env.AWS_SECRET_ACCESS_KEY
	}
});

Google Cloud Storage

await sandbox.mountBucket("my-gcs-bucket", "/data", {
	endpoint: "https://storage.googleapis.com",
	credentials: {
		accessKeyId: env.GCS_ACCESS_KEY_ID,
		secretAccessKey: env.GCS_SECRET_ACCESS_KEY,
	},
});
await sandbox.mountBucket('my-gcs-bucket', '/data', {
	endpoint: 'https://storage.googleapis.com',
	credentials: {
		accessKeyId: env.GCS_ACCESS_KEY_ID,
		secretAccessKey: env.GCS_SECRET_ACCESS_KEY
	}
});

Další poskytovatelé kompatibilní s S3

U poskytovatelů jako Backblaze B2, MinIO, Wasabi nebo dalších použijte standardní vzor připojení:

await sandbox.mountBucket("my-bucket", "/data", {
	endpoint: "https://s3.us-west-000.backblazeb2.com",
	credentials: {
		accessKeyId: env.ACCESS_KEY_ID,
		secretAccessKey: env.SECRET_ACCESS_KEY,
	},
});
await sandbox.mountBucket('my-bucket', '/data', {
	endpoint: 'https://s3.us-west-000.backblazeb2.com',
	credentials: {
		accessKeyId: env.ACCESS_KEY_ID,
		secretAccessKey: env.SECRET_ACCESS_KEY
	}
});

Konfiguraci specifickou pro daného poskytovatele najdete v wiki s3fs-fuse ↗ pro podporované poskytovatele a doporučené příznaky.

Řešení potíží

Chyba: R2 binding nebyl nalezen

Chyba: R2 binding "MY_BUCKET" not found in Worker env

Řešení: Ujistěte se, že váš Worker má r2_buckets vazba a že mountBucket() se používá název bindingu, nikoli název bucketu z dashboardu:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "r2_buckets": [
    {
      "binding": "MY_BUCKET",
      "bucket_name": "my-r2-bucket"
    }
  ]
}
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-r2-bucket"

Připojení R2 bez přihlašovacích údajů selže okamžitě

Řešení: Ujistěte se, že vstupní bod vašeho Workeru exportuje ContainerProxy. Pokud používáte starší verzi Wrangler, může být také potřeba enable_ctx_exports příznak kompatibility.

Chyba chybějících přihlašovacích údajů

Chyba: MissingCredentialsError: No credentials found

Řešení: Tato chyba se týká pouze případů, kdy připojíte vzdálený S3 kompatibilní endpoint nastavením endpoint. Nastavte přihlašovací údaje jako Worker secrets:

npx wrangler secret put R2_ACCESS_KEY_ID
npx wrangler secret put R2_SECRET_ACCESS_KEY

nebo

npx wrangler secret put AWS_ACCESS_KEY_ID
npx wrangler secret put AWS_SECRET_ACCESS_KEY

Chyba selhání připojení

Chyba: S3FSMountError: mount failed

Časté příčiny:

Ověřte konfiguraci vašeho bindingu nebo endpointu:

try {
	await sandbox.mountBucket("MY_BUCKET", "/data");
} catch (error) {
	console.error("Mount failed:", error.message);
	// Check binding name, ContainerProxy export, or remote endpoint configuration
}
try {
	await sandbox.mountBucket('MY_BUCKET', '/data');
} catch (error) {
	console.error('Mount failed:', error.message);
	// Check binding name, ContainerProxy export, or remote endpoint configuration
}

Chyba: cesta je již připojena

Chyba: InvalidMountConfigError: Mount path already in use

Řešení: Nejprve odpojte, nebo použijte jinou cestu:

// Unmount existing
await sandbox.unmountBucket("/data");

// Or use different path
await sandbox.mountBucket("bucket2", "/storage", { endpoint: "..." });
// Unmount existing
await sandbox.unmountBucket('/data');

// Or use different path
await sandbox.mountBucket('bucket2', '/storage', { endpoint: '...' });

Pomalý přístup k souborům

Operace se soubory na připojených bucketech jsou kvůli síťové latenci pomalejší než na lokálním souborovém systému.

Řešení: Zkopírujte často používané soubory lokálně:

// Copy to local filesystem
await sandbox.exec("cp", {
	args: ["/data/large-dataset.csv", "/workspace/dataset.csv"],
});

// Work with local copy (faster)
await sandbox.exec("python", {
	args: ["process.py", "/workspace/dataset.csv"],
});

// Save results back to bucket
await sandbox.exec("cp", {
	args: ["/workspace/results.json", "/data/results/output.json"],
});
// Copy to local filesystem
await sandbox.exec('cp', { args: ['/data/large-dataset.csv', '/workspace/dataset.csv'] });

// Work with local copy (faster)
await sandbox.exec('python', { args: ['process.py', '/workspace/dataset.csv'] });

// Save results back to bucket
await sandbox.exec('cp', { args: ['/workspace/results.json', '/data/results/output.json'] });

Osvědčené postupy