Block & File Storage Basics
The explainer drew the line between block storage (EBS) and a shared filesystem (EFS). This page is the hands-on follow-up: the exact SDK calls to bring each into existence.
Busca en todas las páginas de la documentación
The explainer drew the line between block storage (EBS) and a shared filesystem (EFS). This page is the hands-on follow-up: the exact SDK calls to bring each into existence.
You will create an EBS volume, wait for it, attach it, and inspect it - then create an EFS file system and give it a mount target. Every example mirrors between boto3 and the AWS SDK v3. Remember the boundary from the explainer: these calls provision and connect storage, but the final mount always happens on the instance in shell.
pip install boto3 (boto3 1.43.x, Python 3.10+). TypeScript: npm install @aws-sdk/client-ec2 @aws-sdk/client-efs (Node.js 18+).aws configure, environment variables, or an IAM role - the SDK resolves them automatically.ec2:CreateVolume, ec2:AttachVolume, ec2:DescribeVolumes, and elasticfilesystem:* on the relevant resources.us-east-1, Availability Zone us-east-1a, and an existing VPC subnet for the EFS mount target.CreateVolume provisions a block device. The only required field is AvailabilityZone - a volume lives in exactly one AZ. Add a VolumeType, a Size in GiB, and turn on encryption.
# --- Python (boto3) ---
import boto3
ec2 = boto3.client("ec2", region_name="us-east-1")
vol = ec2.create_volume(
AvailabilityZone="us-east-1a",
Size=20, # GiB
VolumeType="gp3", # general-purpose SSD
Encrypted=True, # encrypt at rest with the default EBS KMS key
)
print(vol["VolumeId"], vol["State"]) # e.g. vol-0abc... creating// --- TypeScript (AWS SDK v3) ---
import { EC2Client, CreateVolumeCommand } from "@aws-sdk/client-ec2";
const ec2 = new EC2Client({ region: "us-east-1" });
const vol = await ec2.send(new CreateVolumeCommand({
AvailabilityZone: "us-east-1a",
Size: 20, // GiB
VolumeType: "gp3", // general-purpose SSD
Encrypted: true, // encrypt at rest with the default EBS KMS key
}));
console.log(vol.VolumeId, vol.State); // e.g. vol-0abc... creatingAvailabilityZone is mandatory and fixes the volume to one AZ for life.gp3 is the modern default - cheaper and more flexible than gp2.Encrypted: true uses the account's default EBS KMS key unless you pass KmsKeyId.creating state; you cannot attach it until it is available.Related: EBS Volumes, Snapshots & Encryption - volume types and KMS keys in depth.
Attaching too early fails. Use the built-in waiter, which polls DescribeVolumes for you until the state flips to available.
# --- Python (boto3) ---
import boto3
ec2 = boto3.client("ec2", region_name="us-east-1")
waiter = ec2.get_waiter("volume_available")
waiter.wait(VolumeIds=["vol-0abc"])
print("volume is available")// --- TypeScript (AWS SDK v3) ---
import { EC2Client, waitUntilVolumeAvailable } from "@aws-sdk/client-ec2";
const ec2 = new EC2Client({ region: "us-east-1" });
await waitUntilVolumeAvailable({ client: ec2, maxWaitTime: 120 }, { VolumeIds: ["vol-0abc"] });
console.log("volume is available");DescribeVolumes retry code.volume_available; v3 exposes waitUntilVolumeAvailable.maxWaitTime (seconds); the poll interval is handled internally.volume_in_use / waitUntilVolumeInUse for after attachment.AttachVolume exposes the volume to a running instance as a block device at a device name like /dev/sdf. The OS then sees it (often as /dev/xvdf or /dev/nvme1n1) and can format and mount it.
# --- Python (boto3) ---
import boto3
ec2 = boto3.client("ec2", region_name="us-east-1")
ec2.attach_volume(VolumeId="vol-0abc", InstanceId="i-0def", Device="/dev/sdf")
print("attached")// --- TypeScript (AWS SDK v3) ---
import { EC2Client, AttachVolumeCommand } from "@aws-sdk/client-ec2";
const ec2 = new EC2Client({ region: "us-east-1" });
await ec2.send(new AttachVolumeCommand({ VolumeId: "vol-0abc", InstanceId: "i-0def", Device: "/dev/sdf" }));
console.log("attached");Device is the requested name; the kernel may surface it under a different path.After attaching, the actual filesystem work happens on the instance, not the SDK:
# On the instance (NOT the SDK): format once, then mount.
sudo mkfs -t xfs /dev/xvdf
sudo mkdir -p /data
sudo mount /dev/xvdf /dataCreateFileSystem provisions a shared filesystem. The CreationToken is a caller-supplied idempotency string: retrying with the same token returns the same file system instead of creating duplicates.
# --- Python (boto3) ---
import boto3, uuid
efs = boto3.client("efs", region_name="us-east-1")
fs = efs.create_file_system(
CreationToken=str(uuid.uuid4()), # idempotency token
PerformanceMode="generalPurpose", # or "maxIO"
ThroughputMode="elastic", # scales automatically
Encrypted=True,
Tags=[{"Key": "Name", "Value": "shared-app-data"}],
)
print(fs["FileSystemId"], fs["LifeCycleState"]) # fs-0123... creating// --- TypeScript (AWS SDK v3) ---
import { EFSClient, CreateFileSystemCommand } from "@aws-sdk/client-efs";
import { randomUUID } from "node:crypto";
const efs = new EFSClient({ region: "us-east-1" });
const fs = await efs.send(new CreateFileSystemCommand({
CreationToken: randomUUID(), // idempotency token
PerformanceMode: "generalPurpose", // or "maxIO"
ThroughputMode: "elastic", // scales automatically
Encrypted: true,
Tags: [{ Key: "Name", Value: "shared-app-data" }],
}));
console.log(fs.FileSystemId, fs.LifeCycleState); // fs-0123... creatingCreationToken makes creation idempotent - safe to retry on a timeout.PerformanceMode is fixed at creation; generalPurpose suits almost everything.ThroughputMode: "elastic" scales throughput to demand with no capacity to plan.creating; it is usable once LifeCycleState is available.Related: EFS Lifecycle Management & Performance Modes - what these modes cost and when to change them.
EFS has no waiter, so poll DescribeFileSystems until it is available, then create a mount target - the NFS endpoint in one subnet that instances connect to. You need one per Availability Zone.
# --- Python (boto3) ---
import boto3, time
efs = boto3.client("efs", region_name="us-east-1")
fs_id = "fs-0123"
# EFS has no waiter - poll until available.
while efs.describe_file_systems(FileSystemId=fs_id)["FileSystems"][0]["LifeCycleState"] != "available":
time.sleep(3)
mt = efs.create_mount_target(
FileSystemId=fs_id,
SubnetId="subnet-0abc", # picks the AZ
SecurityGroups=["sg-0def"], # must allow NFS (TCP 2049)
)
print(mt["MountTargetId"], mt["IpAddress"])// --- TypeScript (AWS SDK v3) ---
import { EFSClient, DescribeFileSystemsCommand, CreateMountTargetCommand } from "@aws-sdk/client-efs";
const efs = new EFSClient({ region: "us-east-1" });
const FileSystemId = "fs-0123";
// EFS has no waiter - poll until available.
let state = "";
do {
const d = await efs.send(new DescribeFileSystemsCommand({ FileSystemId }));
state = d.FileSystems?.[0]?.LifeCycleState ?? "";
if (state !== "available") await new Promise((r) => setTimeout(r, 3000));
} while (state !== "available");
const mt = await efs.send(new CreateMountTargetCommand({
FileSystemId,
SubnetId: "subnet-0abc", // picks the AZ
SecurityGroups: ["sg-0def"], // must allow NFS (TCP 2049)
}));
console.log(mt.MountTargetId, mt.IpAddress);IpAddress is the private IP the NFS client resolves to.With a mount target in place, the instance mounts EFS over NFS - again, a shell step, not the SDK:
# On the instance (NOT the SDK): mount the EFS share over NFS/TLS.
sudo mkdir -p /mnt/efs
sudo mount -t efs -o tls fs-0123:/ /mnt/efsStack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última actualización: 23 jul 2026