or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cloudformation-init.mdec2-instances.mdflow-logs.mdindex.mdlaunch-templates.mdmachine-images.mdnetwork-acl.mdsecurity-groups.mdstorage-volumes.mdsubnets-networking.mduser-data.mdvpc-endpoints.mdvpc-management.mdvpn-connectivity.md
tile.json

storage-volumes.mddocs/

Storage & Volumes

Storage and volume management in AWS CDK EC2 provides comprehensive control over EBS volumes, block devices, encryption, and device mapping for EC2 instances.

Volume Class

The Volume class creates and manages standalone EBS volumes:

class Volume extends Resource implements IVolume {
  constructor(scope: Construct, id: string, props: VolumeProps);
  
  readonly volumeId: string;
  readonly availabilityZone: string;
  readonly encryptionKey?: kms.IKey;
  
  static fromVolumeAttributes(scope: Construct, id: string, attrs: VolumeAttributes): IVolume;
  
  // IAM permissions for volume operations
  grantAttachVolume(grantee: iam.IGrantable, instances?: IInstance[]): iam.Grant;
  grantAttachVolumeByResourceTag(grantee: iam.IGrantable, constructs: Construct[]): iam.Grant;
  grantDetachVolume(grantee: iam.IGrantable, instances?: IInstance[]): iam.Grant;
  grantDetachVolumeByResourceTag(grantee: iam.IGrantable, constructs: Construct[]): iam.Grant;
}

interface IVolume extends IResource {
  readonly volumeId: string;
  readonly availabilityZone: string;
  readonly encryptionKey?: kms.IKey;
  
  grantAttachVolume(grantee: iam.IGrantable, instances?: IInstance[]): iam.Grant;
  grantAttachVolumeByResourceTag(grantee: iam.IGrantable, constructs: Construct[]): iam.Grant;
  grantDetachVolume(grantee: iam.IGrantable, instances?: IInstance[]): iam.Grant;
  grantDetachVolumeByResourceTag(grantee: iam.IGrantable, constructs: Construct[]): iam.Grant;
}

interface VolumeProps {
  readonly availabilityZone: string;
  readonly size: Size;
  readonly volumeType?: VolumeType;
  readonly iops?: number;
  readonly throughput?: number;
  readonly encrypted?: boolean;
  readonly encryptionKey?: kms.IKey;
  readonly snapshotId?: string;
  readonly autoEnableIO?: boolean;
  readonly removalPolicy?: RemovalPolicy;
}

interface VolumeAttributes {
  readonly volumeId: string;
  readonly availabilityZone: string;
  readonly encryptionKey?: kms.IKey;
}

Volume Types

Enumeration of available EBS volume types:

enum VolumeType {
  GENERAL_PURPOSE_SSD = 'gp2',
  GENERAL_PURPOSE_SSD_GP3 = 'gp3',
  PROVISIONED_IOPS_SSD = 'io1',
  PROVISIONED_IOPS_SSD_IO2 = 'io2',
  THROUGHPUT_OPTIMIZED_HDD = st1',
  COLD_HDD = 'sc1',
  MAGNETIC = 'standard'
}

enum EbsDeviceVolumeType {
  GENERAL_PURPOSE_SSD = 'gp2',
  GENERAL_PURPOSE_SSD_GP3 = 'gp3',
  PROVISIONED_IOPS_SSD = 'io1',
  PROVISIONED_IOPS_SSD_IO2 = 'io2',
  THROUGHPUT_OPTIMIZED_HDD = 'st1',
  COLD_HDD = 'sc1',
  MAGNETIC = 'standard'
}

Block Device Volumes

Class for creating block device mappings:

class BlockDeviceVolume {
  static ebs(volumeSize: number, options?: EbsDeviceOptions): BlockDeviceVolume;
  static ebsFromSnapshot(snapshotId: string, options?: EbsDeviceSnapshotOptions): BlockDeviceVolume;
  static ephemeral(volumeIndex: number): BlockDeviceVolume;
}

interface BlockDevice {
  readonly deviceName: string;
  readonly volume: BlockDeviceVolume;
  readonly mappingEnabled?: boolean;
}

interface EbsDeviceOptions {
  readonly encrypted?: boolean;
  readonly kmsKey?: kms.IKey;
  readonly deleteOnTermination?: boolean;
  readonly iops?: number;
  readonly throughput?: number;
  readonly volumeType?: EbsDeviceVolumeType;
}

interface EbsDeviceSnapshotOptions extends EbsDeviceOptions {
  readonly volumeSize?: number;
}

Usage Examples

Basic Volume Creation

import * as ec2 from "@aws-cdk/aws-ec2";
import * as cdk from "@aws-cdk/core";

// Basic EBS volume
const basicVolume = new ec2.Volume(this, "BasicVolume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(100)
});

// GP3 volume with custom IOPS and throughput
const gp3Volume = new ec2.Volume(this, "GP3Volume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(500),
  volumeType: ec2.VolumeType.GENERAL_PURPOSE_SSD_GP3,
  iops: 3000,
  throughput: 125
});

// IO2 volume for high IOPS workloads
const io2Volume = new ec2.Volume(this, "IO2Volume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(100),
  volumeType: ec2.VolumeType.PROVISIONED_IOPS_SSD_IO2,
  iops: 10000
});

Encrypted Volumes

import * as kms from "@aws-cdk/aws-kms";

// Volume with default encryption
const encryptedVolume = new ec2.Volume(this, "EncryptedVolume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(100),
  encrypted: true
});

// Volume with customer-managed KMS key
const kmsKey = new kms.Key(this, "VolumeKey", {
  description: "EBS Volume encryption key"
});

const customerEncryptedVolume = new ec2.Volume(this, "CustomerEncryptedVolume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(200),
  encrypted: true,
  encryptionKey: kmsKey
});

Volume from Snapshot

// Volume created from existing snapshot
const snapshotVolume = new ec2.Volume(this, "SnapshotVolume", {
  availabilityZone: "us-east-1a",
  snapshotId: "snap-12345678",
  size: cdk.Size.gibibytes(100)
});

Instance with Block Device Mappings

const vpc = new ec2.Vpc(this, "MyVpc");

const instance = new ec2.Instance(this, "InstanceWithStorage", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(50, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true,
        deleteOnTermination: true
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        iops: 3000,
        throughput: 125,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdc",
      volume: ec2.BlockDeviceVolume.ebs(500, {
        volumeType: ec2.EbsDeviceVolumeType.THROUGHPUT_OPTIMIZED_HDD
      })
    }
  ]
});

High-Performance Storage Configuration

// High IOPS database instance
const databaseInstance = new ec2.Instance(this, "DatabaseInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.XLARGE4),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ebs(1000, {
        volumeType: ec2.EbsDeviceVolumeType.PROVISIONED_IOPS_SSD_IO2,
        iops: 20000,
        encrypted: true
      })
    }
  ],
  vpcSubnets: {
    subnetType: ec2.SubnetType.PRIVATE_WITH_NAT
  }
});

Volume with Snapshot Source

// Create volume from snapshot with specific options
const restoredVolume = ec2.BlockDeviceVolume.ebsFromSnapshot("snap-12345678", {
  volumeSize: 200, // Increase size from original snapshot
  volumeType: ec2.EbsDeviceVolumeType.GP3,
  iops: 3000,
  encrypted: true,
  deleteOnTermination: false
});

const instanceFromSnapshot = new ec2.Instance(this, "RestoredInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: restoredVolume
    }
  ]
});

Ephemeral Storage

// Instance with ephemeral (instance store) volumes
const instanceStoreInstance = new ec2.Instance(this, "InstanceStoreInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.I3, ec2.InstanceSize.LARGE),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(50, {
        volumeType: ec2.EbsDeviceVolumeType.GP3
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ephemeral(0)
    },
    {
      deviceName: "/dev/xvdc", 
      volume: ec2.BlockDeviceVolume.ephemeral(1)
    }
  ]
});

Volume Access Permissions

import * as iam from "@aws-cdk/aws-iam";

const dataVolume = new ec2.Volume(this, "DataVolume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(500),
  volumeType: ec2.VolumeType.GP3
});

const instance = new ec2.Instance(this, "Instance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  availabilityZone: "us-east-1a"
});

// Grant instance permission to attach/detach the volume
dataVolume.grantAttachVolume(instance, [instance]);
dataVolume.grantDetachVolume(instance, [instance]);

// Create IAM role with volume permissions
const volumeRole = new iam.Role(this, "VolumeRole", {
  assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com")
});

dataVolume.grantAttachVolume(volumeRole);
dataVolume.grantDetachVolume(volumeRole);

Multi-Volume Setup for Different Workloads

// Web server with standard storage
const webInstance = new ec2.Instance(this, "WebInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda", // Root volume
      volume: ec2.BlockDeviceVolume.ebs(30, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdb", // Application data
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true
      })
    }
  ]
});

// Database server with high-performance storage
const dbInstance = new ec2.Instance(this, "DatabaseInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.XLARGE2),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda", // Root volume
      volume: ec2.BlockDeviceVolume.ebs(50, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdb", // Database data - high IOPS
      volume: ec2.BlockDeviceVolume.ebs(500, {
        volumeType: ec2.EbsDeviceVolumeType.PROVISIONED_IOPS_SSD_IO2,
        iops: 15000,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdc", // Database logs - optimized for throughput
      volume: ec2.BlockDeviceVolume.ebs(200, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        throughput: 250,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdd", // Backup storage - cost-optimized
      volume: ec2.BlockDeviceVolume.ebs(1000, {
        volumeType: ec2.EbsDeviceVolumeType.THROUGHPUT_OPTIMIZED_HDD
      })
    }
  ],
  vpcSubnets: {
    subnetType: ec2.SubnetType.PRIVATE_WITH_NAT
  }
});

Launch Template with Block Devices

const launchTemplate = new ec2.LaunchTemplate(this, "MyLaunchTemplate", {
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(50, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true,
        deleteOnTermination: true
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        iops: 3000,
        throughput: 125,
        encrypted: true,
        deleteOnTermination: false // Preserve data volume
      })
    }
  ]
});

Volume Encryption with Cross-Region Keys

// Import KMS key from another region
const crossRegionKey = kms.Key.fromKeyArn(
  this,
  "CrossRegionKey",
  "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012"
);

const crossRegionVolume = new ec2.Volume(this, "CrossRegionVolume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(100),
  encrypted: true,
  encryptionKey: crossRegionKey
});

Volume with Lifecycle Management

const managedVolume = new ec2.Volume(this, "ManagedVolume", {
  availabilityZone: "us-east-1a",
  size: cdk.Size.gibibytes(500),
  volumeType: ec2.VolumeType.GP3,
  encrypted: true,
  removalPolicy: cdk.RemovalPolicy.RETAIN // Prevent accidental deletion
});

// Tag volume for backup automation
cdk.Tags.of(managedVolume).add("Backup", "Daily");
cdk.Tags.of(managedVolume).add("Environment", "Production");

Importing Existing Volumes

// Import existing volume by ID
const existingVolume = ec2.Volume.fromVolumeAttributes(this, "ExistingVolume", {
  volumeId: "vol-12345678",
  availabilityZone: "us-east-1a"
});

// Import encrypted volume with key
const existingEncryptedVolume = ec2.Volume.fromVolumeAttributes(this, "ExistingEncryptedVolume", {
  volumeId: "vol-87654321",
  availabilityZone: "us-east-1a",
  encryptionKey: kms.Key.fromKeyId(this, "ImportedKey", "alias/my-volume-key")
});

Performance Optimization Examples

// High-throughput workload
const throughputOptimizedInstance = new ec2.Instance(this, "ThroughputInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.D3, ec2.InstanceSize.XLARGE4),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ebs(2000, {
        volumeType: ec2.EbsDeviceVolumeType.THROUGHPUT_OPTIMIZED_HDD
      })
    }
  ]
});

// Low-latency, high-IOPS workload
const highIopsInstance = new ec2.Instance(this, "HighIopsInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.I3, ec2.InstanceSize.XLARGE2),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ebs(1000, {
        volumeType: ec2.EbsDeviceVolumeType.PROVISIONED_IOPS_SSD_IO2,
        iops: 32000
      })
    }
  ]
});

Best Practices

  1. Volume Type Selection: Choose appropriate volume types based on workload requirements (IOPS, throughput, cost)
  2. Encryption: Always encrypt volumes containing sensitive data
  3. Sizing: Size volumes appropriately to meet performance and cost requirements
  4. Backup Strategy: Implement regular snapshot schedules for data protection
  5. Performance Monitoring: Monitor volume performance metrics and adjust as needed
  6. Cost Optimization: Use appropriate volume types to balance performance and cost
  7. Lifecycle Management: Set appropriate deletion policies and retention rules
  8. Security: Use IAM policies to control volume access and operations
  9. Multi-AZ Deployment: Consider cross-AZ volume placement for disaster recovery
  10. Capacity Planning: Plan for future storage growth and performance needs