© Brian Beach, Steven Armentrout, Rodney Bozo, Emmanuel Tsouris 2019
B. Beach et al.Pro PowerShell for Amazon Web Serviceshttps://doi.org/10.1007/978-1-4842-4850-8_4

4. Elastic Block Storage

Brian Beach1 , Steven Armentrout2, Rodney Bozo3 and Emmanuel Tsouris4
(1)
Raleigh, NC, USA
(2)
Mountlake Terrace, WA, USA
(3)
Sterling, VA, USA
(4)
North Bend, WA, USA
 

In the last chapter, we learned how to launch and manage instances. In this chapter, we will focus on the volumes, or disks, attached to the instance. We will learn how to customize and add additional volumes at launch. Then we will look at modifying the volumes after launch. This chapter will also cover snapshots. Snapshots are a point-in-time copy of a volume, often used for backups. Snapshots can be used to create copies of volumes or to recover from a disaster. We will talk about using snapshots to create a backup of a volume and how to restore a volume when a disaster occurs.

Let’s start with a little background. Volumes are based on a technology Amazon calls Elastic Block Storage (EBS). EBS is network-attached storage used by EC2 instances. Like iSCSI in a traditional data center, EBS shares bandwidth with other network-attached storage traffic. This means performance is affected by network load. We will see how to configure quality of service to guarantee the minimum performance of our volumes.

EBS volumes are redundant within an availability zone. Therefore, there is no need to create RAID arrays of EBS disks within the operating system. Remember that an availability zone is a single data center. Despite the redundancy EBS provides, it is possible to lose an entire availability zone in a disaster. Therefore, we still need to back up our volumes using snapshots. Snapshots are backups of volumes stored in the Simple Storage Service (S3). (We will talk about S3 in detail in Chapter 11.) Each snapshot is stored in multiple availability zones within a region to provide very high durability. In addition, we will see how to copy snapshots from one region to another.

Let’s get started by building on our experience in Chapter 3. In the next section, we will extend our launch scripts to control volumes at launch.

Managing Volumes at Launch

In the last chapter, we discussed launching a new EC2 instance. Remember when we skipped over a few of the screens in the wizard. Let’s return to the wizard and look at the Add Storage configuration screen. This screen allows us to specify the number, size, and performance characteristics of the volumes that will be attached to the instance.

Open the AWS EC2 Management Console and click the Launch Instance button on the EC2 dashboard. Navigate through the wizard and stop on the Add Storage screen (see Figure 4-1). This screen lists the default volumes that come with the Amazon Machine Image (AMI) we choose. Remember that an AMI is the template that describes an instance as well as snapshots of its volume data. Most Windows images include a 30GB root volume. SQL images are larger, and most Linux distributions are significantly smaller.
../images/319650_2_En_4_Chapter/319650_2_En_4_Fig1_HTML.jpg
Figure 4-1

Add Storage configuration

We can change the size of the root volume by simply typing into the text box under the heading Size (GiB). The initial size is the minimum size the AMI snapshot requires and cannot be reduced. Thirty GB is good enough for most Windows applications, but some applications, such as SQL Server, require more storage and will start at a higher value. A single volume can be set between 1GB and 16TB. In addition, we can configure the IO operations per second (IOPS) for a volume. (We will talk about provisioned IOPS later in this chapter).

We can also choose to delete the volume on termination. If we check this box, the volume will be automatically deleted when we terminate the instance. In general, the root volume is configured to auto delete by default, and any additional volumes we attach are not.

What’s a Gibibyte (GIB)?

If we look closely at Figure 4-2, we may notice the Volume size is measured in GiB, which is the abbreviation for gibibyte. A gibibyte (GiB) is closely related to, but not equal to, a gigabyte (GB).

We know that 1KB = 1024 bytes but in other scientific disciplines 1K = 1000. Computer scientists prefer 1024 because it is a power of 2 (2^10 = 1024).

Amazon is using the unambiguous gibibyte. In these examples we will use the old GB but really mean GiB.

Manipulating the root volume in PowerShell is verbose, but straightforward. PowerShell uses .NET objects to describe the drive configuration. We simply pass the .NET object to the New-EC2Instance we used in Chapter 3.

First, we use the Amazon.EC2.Model.EbsBlockDevice object to describe the volume. Here we want a 55GB GP2 volume, which does not use provisioned IOPS. In addition, we want the volume to be deleted when we terminate the instance.
$Volume = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume.VolumeSize = 55
$Volume.VolumeType = 'GP2'
$Volume.DeleteOnTermination = $True
Next, we use the Amazon.EC2.Model.BlockDeviceMapping object to describe how the volume should be attached to the instance. The root volume is always attached to “/dev/sda1”. Notice that we are passing the EbsBlockDevice object created by the preceding code.
$Mapping = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping.DeviceName = '/dev/sda1'
$Mapping.Ebs = $Volume
Finally, we call New-EC2Instance and include the BlockDeviceMapping parameter describing how we want the volume configured.
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1 -BlockDeviceMapping $Mapping
$Instance = $Reservation.RunningInstance[0]
Write-output $Instance.InstanceId
We can also add additional volumes to the instance at launch. See Figure 4-2. Windows instances will support up to 26 total volumes. The New Instance Wizard allows us to add additional volumes using the Add New Volume button in the Add Storage Configuration page. Most of these options are the same as the root volume with a couple of differences, described next.
../images/319650_2_En_4_Chapter/319650_2_En_4_Fig2_HTML.jpg
Figure 4-2

EBS volumes

We can choose to use a snapshot to initialize our disk. Recall that a snapshot is a copy of a volume at a specific point in time. The root volume always uses the snapshot specified for the AMI we selected, but additional volumes can use any snapshot. We can choose our own snapshot, or there are numerous interesting datasets available for public use. Leaving the snapshot entry field blank results in a new empty volume.

We must set a device name. The device name describes how the EBS volume is attached to the instance. This is like describing which port the disk is plugged into on a physical machine. For EBS volumes we should use xvd[b-z]. Just use them in order: xvdb, xvde, xvdf, and so on. These device names are auto-filled in using the console for Windows AMIs but need to be specified when using PowerShell.

Additional volumes are handled just like the root volume when using PowerShell. For each additional volume, we create another EbsBlockDevice and BlockDeviceMapping objects. Note that the root volume is always attached at device name “/dev/sda1” and the second EBS disk is attached at “xvdb”.

In the following example, note that we have chosen to delete the root volume when the instance is terminated, but we will keep the second volume by setting DeleteOnTermination attribute to false. We separate the mapping objects by commas when calling New-EC2Instance to create an array of mappings.
$Volume1 = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume1.DeleteOnTermination = $True
$Volume1.VolumeSize = 30
$Volume1.VolumeType = 'gp2'
$Mapping1 = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping1.DeviceName = '/dev/sda1'
$Mapping1.Ebs = $Volume1
$Volume2 = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume2.DeleteOnTermination = $False
$Volume2.VolumeSize = 100
$Volume2.VolumeType = 'gp2'
$Mapping2 = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping2.DeviceName = 'xvdf'
$Mapping2.Ebs = $Volume2
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1 -BlockDeviceMapping $Mapping1, $Mapping2
$Instance = $Reservation.RunningInstance[0]
Write-output $Instance.InstanceId
If we want to use a snapshot to initialize the second volume, we can use the SnapshotId parameter. We can use a snapshot we created or use one of the many already available. For example, the following partial code will generate a 100GB volume containing the Windows 2016 installation media from a snapshot found in Northern Virginia. Note that there are no CD/DVD drives in EC2 instances. (Later in this chapter, we will talk more about discovering the numerous snapshots available with AWS).
$MediaSnapshot = Get-EC2Snapshot -Filter @(@{name='description';value="Windows 2016 English Installation Media"},@{name='owner-alias';value="amazon"})
$Volume2 = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume2.DeleteOnTermination = $False
$Volume2.VolumeSize = 100
$Volume2.VolumeType = 'gp2'
$Volume2.SnapshotId = $MediaSnapshot[0].SnapshotId

When launching some instance types in the console such as m5d or i2, we will see additional volume types. In the Add Storage launch step, they will appear with Volume Type names like “Instance Store 0” or “ephemeral0”. These are what is known as ephemeral volumes. Ephemeral volumes allow us to access disks local to the host server. While EBS volumes are network-attached storage, ephemeral (instance store) volumes are directly attached storage.

There can be significant performance gains using the directly attached ephemeral volumes, but this approach comes with some limitations. The ephemeral drives are not persisted when the instance is stopped. If an instance is stopped or placed into a shutdown state, the data is simply deleted. Therefore, ephemeral drives are good only for temporary storage such as a cache or when used in a high availability or clustering architecture to preserve the data. Note however this data loss does not happen during a reboot since the instance never reaches a stopped state.

If we selected a micro instance, there are no ephemeral volumes. In Figure 4-3, we have chosen an i2.xlarge that includes an 800GB ephemeral SSD. We also added a second 100GB EBS volume. Note that the ephemeral drives are attached by default. Some ephemeral drives can be removed if we want, but we don’t pay anything extra by leaving them attached. Just be careful that we’re not using the ephemeral drives when we expect to be using an EBS volume.
../images/319650_2_En_4_Chapter/319650_2_En_4_Fig3_HTML.jpg
Figure 4-3

Ephemeral volumes

When we create an instance using PowerShell, the ephemeral drives are also attached automatically. There is no reason to remove them, but we can do so by creating a BlockDeviceMapping with NoDevice set to true. Note in the following partial code example that there is no EbsBlockDevice object in this case.
$Mapping = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping.DeviceName = 'xvdca'
$Mapping.NoDevice = $true
Figure 4-4 shows the disk configuration of a Windows Server 2016 instance with all three volume types: a 30GB root volume, one additional 100GB EBS volume, and an 800GB ephemeral volume. Not all instance types have 800GB ephemeral volumes. Some, such as the t2.micro, have no ephemeral volumes. Other instance types can have as much as 48TB total of ephemeral storage.
../images/319650_2_En_4_Chapter/319650_2_En_4_Fig4_HTML.jpg
Figure 4-4

EBS and ephemeral volumes as seen by Windows

As we have seen, Amazon makes it easy to manage volumes when launching an instance. Unfortunately, we don’t always know exactly what the volumes should look like. We do our best to estimate how big each volume needs to be, but requirements change. New software is installed, usage patterns change, and so on.

Encrypting Volumes at Launch

When configuring and adding volumes in the Add Storage step, an encrypted selection exists. Enabling this setting will enable data at reset security by encrypting our volume and resultant snapshots with keys defined in the AWS Key Management Service (KMS) . This will enable an extra layer of defense to protect our data and to meet regulatory or compliance needs. Enabling encryption does result in some changes to be aware of:
  • Encrypts data at rest inside the volume.

  • Encrypts all data moving between the volume and the instance.

  • Encrypts all snapshots created from the volume.

  • Encrypts all volumes created from those snapshots.

  • Once encrypted, a volume cannot be unencrypted.

  • Not all instance types support encrypted volumes.

  • Only new empty volumes can be encrypted.

  • Encrypted volumes and snapshots have sharing restrictions.

  • Encryption is limited to EBS volumes only and requires an encryption key from the AWS Key Management Service (KMS).

Key Management Service is outside the scope of this chapter so more information about using KMS for EBS encryption can be found at https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html .

To encrypt a volume using PowerShell, we first need to find the KMS KeyId. We will use the default EBS key by searching KMS for the key with alias “alias/aws/ebs” and getting its TargetKeyId property. We then will create a secondary 100GB EBS volume with encryption enabled using this key ID.

This default EBS encryption key gets created the first time we launch an instance from the console and have encryption enabled set on a volume. If the key cannot be found, try launching an instance with an encrypted volume from the console first.
$KMSKeyId = (Get-KMSAliasList | Where-Object {$_.AliasName -eq "alias/aws/ebs"}).TargetKeyId
$Volume1 = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume1.DeleteOnTermination = $True
$Volume1.VolumeSize = 30
$Volume1.VolumeType = 'gp2'
$Mapping1 = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping1.DeviceName = '/dev/sda1'
$Mapping1.Ebs = $Volume1
$Volume2 = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume2.DeleteOnTermination = $False
$Volume2.VolumeSize = 100
$Volume2.VolumeType = 'gp2'
$Volume2.Encrypted = $true
$Volume2.KmsKeyId = $KMSKeyId
$Mapping2 = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping2.DeviceName = 'xvda'
$Mapping2.Ebs = $Volume2
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1 -BlockDeviceMapping $Mapping1,$Mapping2
$Instance = $Reservation.RunningInstance[0]

In the next section, we will discuss how to add volumes to a running instance, and in Exercise 4.1 we will resize a volume.

Adding a Volume to a Running Instance

Often, we want to add a volume after the instance is already running. We can create a new volume and attach it to a running instance at any time.

To create a volume from the EC2 Web Console, on the left side click the plus sign next to ELASTIC BLOCK STORE field to expand it and select Volumes. Click the Create Volume button on the Volumes page that opens. The Create Volume page will open, and we will need to specify all the options we discussed earlier, plus the Availability Zone (see Figure 4-5). Remember from Chapter 1 that an availability zone is one of many data centers in a region, so we can only attach a volume to an instance in the same availability zone.
../images/319650_2_En_4_Chapter/319650_2_En_4_Fig5_HTML.jpg
Figure 4-5

Creating a new volume

Creating a volume in PowerShell is simple. But before we attach volumes, let’s create a new Windows Server 2016 instance:
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1
$Instance = $Reservation.RunningInstance[0]
Now we find the availability zone of our new instance by getting the AvailabilityZone property of the subnet we launched in.
$AvailZone = (Get-EC2Subnet -SubnetId $Instance.SubnetId).AvailabilityZone
The following example creates a new 100GB empty volume:
$LargeVolume = New-EC2Volume -Size 100 -AvailabilityZone $AvailZone -VolumeType gp2
If we want to use a snapshot to initialize our volume, just specify the snapshot ID. This example creates a new volume with the public Windows 2016 install media:
$MediaSnapshot = Get-EC2Snapshot -Filter @(@{name='description';value="Windows 2016 English Installation Media"},@{name='owner-alias';value="amazon"})
$SnapshotVolume = New-EC2Volume -SnapshotId $MediaSnapshot[0].SnapshotId -AvailabilityZone $AvailZone -VolumeType gp2
Once the volumes are created, we can attach them to an instance using the Add-EC2Volume command. In the following example, we use a while loop to wait for the volumes to become available. Then we attach them to an instance using Add-EC2Volume and wait for them to become in use.
While ($addvolumes.status -ne "available") {Start-Sleep -Seconds 10; $addvolumes = Get-EC2Volume -VolumeIds $LargeVolume.VolumeId,$SnapshotVolume.VolumeId }
Add-EC2Volume -VolumeId $LargeVolume.VolumeId -InstanceId $Instance.InstanceId -Device 'xvdg'
Add-EC2Volume -VolumeId $SnapshotVolume.VolumeId -InstanceId $Instance.InstanceId -Device 'xvdh'
While ($usedvolumes.status -ne "in-use") {Start-Sleep -Seconds 10; $usedvolumes = Get-EC2Volume -VolumeIds $LargeVolume.VolumeId,$SnapshotVolume.VolumeId}
Once we are done with the volumes, we can detach them from the instance using Dismount-EC2Volume. We can also delete them using Remove-EC2Volume. We will again use a while loop to check that the volumes are in an available state before deleting them. If the volumes fail to reach an available state after a minute, they may be locked by the OS on the instance. It’s best practice to offline volumes in the instance before running the EC2 dismount. Ensure the volumes are offline in the instance and restart the following code again:
Dismount-EC2Volume -VolumeId $LargeVolume.VolumeId
Dismount-EC2Volume -VolumeId $SnapshotVolume.VolumeId
While ($detachvolumes.status -ne "available") {Start-Sleep -Seconds 10; $detachvolumes = Get-EC2Volume -VolumeIds $LargeVolume.VolumeId,$SnapshotVolume.VolumeId }
Remove-EC2Volume -VolumeId $LargeVolume.VolumeId –Force
Remove-EC2Volume -VolumeId $SnapshotVolume.VolumeId –Force

Managing Quality of Service

Some instances – database servers, for example – are more IO intensive and some instance workloads are more throughput intensive, while others still just need low-cost storage for long-term data archiving. AWS offers several options for EBS storage types, and they each have unique benefits:
  • General Purpose SSD (GP2) is the default general purpose storage type recommended for most workloads. It’s a SSD-based storage with a balance between price and performance. We get three IOPS per GB for minimum baseline performance and many thousands of burst IOPS per volume.

  • Throughput Optimized HDD (st1) are low-cost volumes suited for throughput intensive workloads.

  • Cold HDD (sc1) is the lowest-cost storage option recommended for infrequently accessed large volumes of data.

  • Provisioned IOPS SSD (io1) is designed for mission critical high-throughput and low-latency workloads. Like GP2, io1 is SSD based but allows for much higher baseline performance that’s explicitly defined for the volume.

  • Io1 volumes allow for up to 50 IOPS per GB sustained performance with a maximum of 64,000 IOPS per volume on Nitro-based instance types.

Aside from choosing the proper storage type for our workload, we also need to consider that EBS volumes are shared network storage. Obviously, there are many AWS tenants competing for the same resources. In addition, the EBS traffic is typically competing for bandwidth with the other traffic to and from our own instance. EBS-optimized instances get guaranteed network bandwidth between the instance and the EBS volumes. This ensures that we get the expected performance regardless of how congested the network gets.

To create an EBS-optimized instance, we can launch our instance on an instance type that is EBS Optimized by default or we can enable the EbsOptimized flag on a new or existing instance. Note that most current generation instance types enable EBS Optimization by default and not all instance types support EBS optimization. In the following example, we are launching an EBS-optimized instance on m1.large that does support it but is not enabled by default.
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' –InstanceType 'm1.large' -MinCount 1 -MaxCount 1 -EbsOptimized:$true
$Instance = $Reservation.RunningInstance[0]
In the following example, we are going to launch a new instance with a Provisioned IOPS SSD (io1) root volume. To specify IOPS at launch time, use the EbsBlockDevice object. Simply, set the volume type to “io1” and specify the IOPS desired. In the following example, we are launching a new EBS-optimized instance with a root volume of 30GB provisioned at 1000 IOPS.
$Volume = New-Object Amazon.EC2.Model.EbsBlockDevice
$Volume.DeleteOnTermination = $True
$Volume.VolumeSize = 30
$Volume.VolumeType = 'io1'
$volume.IOPS = 1000
$Mapping = New-Object Amazon.EC2.Model.BlockDeviceMapping
$Mapping.DeviceName = '/dev/sda1'
$Mapping.Ebs = $Volume
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 'm1.large' -MinCount 1 -MaxCount 1 -BlockDeviceMapping $Mapping -EbsOptimized:$true
$Instance = $Reservation.RunningInstance[0]
We can also create a new volume with provisioned IOPS and attach it to an existing instance:
$AvailZone = (Get-EC2Subnet -SubnetId $Instance.SubnetId).AvailabilityZone
$Volume = New-EC2Volume -Size 100 -AvailabilityZone $AvailZone -VolumeType io1 -IOPS 2000
We could attach this volume to an instance the same way we did in the previous section:
Add-EC2Volume -VolumeId $Volume.VolumeId -InstanceId $Instance.InstanceId -Device 'xvdf'

Now we know how to create and manage volumes. We can add volumes when launching a new instance or add a volume to a running instance. We can also manage the quality of service to guarantee performance. Next, we will talk about snapshots. Snapshots allow us to take a point-in-time copy of a volume.

Working with Snapshots

Snapshots are used to create a point-in-time copy of a volume often used for backup and recovery. Creating a new snapshot is simple. Just call New-EC2Snapshot and pass the ID of the volume. We can also add an optional description. For example, let’s assume we are about to do a risky upgrade and we want to take a snapshot of an instance. First, stop the instance and create the snapshot of its root volume. Note that our instance and volumes will have different IDs than the ones explicitly defined in the following examples:
$Snapshot = New-EC2Snapshot -VolumeId vol-0b8daf5e53c94fd69 -Description 'Before upgrade to version 3.22'
Now, let’s assume that our suspicions were correct, and we need to roll back the change. We already know how to restore a snapshot. We did it in the last section. We just create a new volume using the snapshot and verify that the volume is in the same availability zone as the instance we want to restore.
$Volume = New-EC2Volume  -AvailabilityZone us-east-1b -VolumeType gp2 -SnapshotId $Snapshot.SnapshotId

Note that we did not define a volume size here. When specifying a snapshot in a new volume creation, if the volume size is not set, then the new volume is automatically set to the snapshot size.

We cannot overwrite the contents of an existing volume. A restore always creates a new volume. Therefore, to replace the volume of an existing instance, we must detach the current volume and replace it with the one restored from the snapshot. Let’s replace it with the restored volume. Note that this is the root volume and the instance should be stopped first.
Dismount-EC2Volume -VolumeId vol-0b8daf5e53c94fd69
While($BadVolume.Status -ne 'available') {Start-Sleep -Seconds 10; $BadVolume = Get-EC2Volume  -VolumeId vol-0b8daf5e53c94fd69}
Add-EC2Volume -VolumeId $Volume.VolumeId -InstanceId i-0af9c78cd49747e08 -Device '/dev/sda1'
While($Volume.Status -ne 'in-use') {Start-Sleep -Seconds 10; $Volume = Get-EC2Volume  -VolumeId $Volume.VolumeId }
Remove-EC2Volume -VolumeId vol-0b8daf5e53c94fd69 -Force
Now, boot the instance, and we are back where we were before the upgrade. Let’s assume the upgrade works the second time, and we want to delete the snapshot. Just use Remove-EC2Snapshot:
Remove-EC2Snapshot -SnapshotId $Snapshot.SnapshotId –Force

Before we move on, let’s talk about backup strategy. Many firms are accustomed to taking tape backups each night and storing them offsite. Can a snapshot replace offsite tape backups? Absolutely! Snapshots are stored in the AWS S3. S3 data is replicated three times across multiple availability zones within a region. This provides 99.999999999% durability. But, let’s say we have a truly critical application that cannot stand an outage. It is possible that an entire region will suffer a power outage or other catastrophe that could bring our application down temporarily.

We can optionally copy the snapshot to another region using snapshot copy.

Let’s assume we have an application running in Northern Virginia (us-east-1) and want to copy it to Northern California (us-west-1). The copy is always initiated from the destination region.
Copy-EC2Snapshot -SourceRegion 'us-east-1' -SourceSnapshotId ‘snap-0f390256dde249d88' -Region 'us-west-1' -Description 'Copied from Northern Virginia'

Now, in the unlikely case that all the data in the Northern Virginia region was destroyed, we could recover our application in Northern California. While the previous examples are an effective strategy as a backup solution, there are some more advanced strategies using AWS Systems Manager that we will learn about in Chapter 16. To learn how Systems Manager Run command can manage backups, see https://docs.aws.amazon.com/systems-manager/latest/userguide/integration-vss.html .

Managing Public Snapshots

At the beginning of this chapter, we created a volume that included the Windows 2016 install media from a public snapshot. There are numerous snapshots available for our use. We can get a list by running Get-EC2Snapshot, but be warned that there are a lot of snapshots to sift through, and not all of them are from trustworthy sources.

To get a list of snapshots provided by Amazon, filter on the owner-alias property. This will narrow the list considerably. In the following example, we use two filters when looking for Windows 2016 media.
Get-EC2Snapshot -Filter @(@{name='description';value="Windows 2016∗Installation Media"},@{name='owner-alias';value="amazon"})
In addition to software, Amazon has numerous datasets that can be used for testing. For example, the following command will return US Census snapshot data located in the us-east-1 region:
Get-EC2Snapshot -Filter @(@{name='description';value="* US Census (Windows)"},@{name='owner-alias';value="amazon"}) -Region us-east-1
If we have an interesting dataset to make available to others, we can share our snapshots. We can choose to share with a specific AWS account or with all AWS accounts. If we want to share our snapshot with everyone, we call Edit-EC2SnapshotAttribute with the UserGroup attribute set to all. The following examples will also use a sample snapshot ID. To try these examples, we just need to replace the snapshot ID with our own but keep in mind that this snapshot will be usable by anyone within AWS. Share the snapshot and check the permissions using the Get-EC2SnapshotAttribute cmdlet.
Edit-EC2SnapshotAttribute –SnapshotId 'snap-0f390256dde249d88' -Attribute 'createVolumePermission' -OperationType 'add' -UserGroup 'all'
(Get-EC2SnapshotAttribute -Attribute 'createVolumePermission' -SnapshotId snap-0f390256dde249d88).CreateVolumePermissions
Note that changes to permissions can take some time to propagate. Some upstream services and the EC2 Console may take several minutes before the snapshot can be accessed in other accounts. A direct describe call using the snapshot ID is the best way to get the most accurate permission settings. To remove the public access, rerun the command but change the OperationType value to remove.
Edit-EC2SnapshotAttribute –SnapshotId 'snap-0f390256dde249d88' -Attribute 'createVolumePermission' -OperationType 'remove' -UserGroup 'all'
If we prefer to share with a specific account, use the UserId attribute and supply the account number. We will again read back the snapshot CreateVolumePermissions attribute to validate our change. Note that we must remove the dashes from the account number, for example, if the account number is 1234-1234-1234.
Edit-EC2SnapshotAttribute –SnapshotId 'snap-0f390256dde249d88' -Attribute 'createVolumePermission' -OperationType 'add' -UserId '123412341234'
(Get-EC2SnapshotAttribute -Attribute 'createVolumePermission' -SnapshotId snap-0f390256dde249d88).CreateVolumePermissions
If we want to remove a user’s permission, once again set the OperationType to “remove”. For example:
Edit-EC2SnapshotAttribute –SnapshotId 'snap-0f390256dde249d88' -Attribute 'createVolumePermission' -OperationType 'remove' -UserId '123412341234'
And, if we want to remove all permissions to a snapshot, use the Reset-EC2SnapshotAttribute cmdlet. For example:
Reset-EC2SnapshotAttribute –SnapshotId 'snap-0f390256dde249d88' -Attribute 'createVolumePermission'

In this chapter, we learned about volumes and snapshots. We learned how to add volumes to an instance and make copies of a volume using snapshots. In the first exercise, we will build a script to resize a volume. In the second exercise, we will build a script to back up all the volumes in an account.

Exercise 4.1: Resizing a Volume

Over time, we may find that a volume is not big enough, and we need to resize it. In this example we will build a script that automates the process. The exercise script takes two parameters, the volume ID we want to resize and the incremental size in Gigabytes we want to add.
Param(
    [string][Parameter(Mandatory=$True)] $VolumeId,
    [int][Parameter(Mandatory=$True)] $GBIncrement
)
Before we start, let’s get a reference to the volume so we know how it is attached and what instance it is attached to.
$TargetVolume = Get-EC2Volume -Volume $VolumeId
$Attachment = $TargetVolume.Attachment[0]
Note that we cannot make the volume smaller as there would not be room for the partition or snapshot data.
[int]$NewSize = $TargetVolume.Size + $GBIncrement
If ($Attachment.InstanceId -ne $null)
{
    If ((Get-EC2InstanceStatus $Attachment.InstanceId).InstanceState -ne "stopped")
    {
        Write-Warning "Instance not in a stopped state. File system integrity errors may be exist in the snapshot." -WarningAction Continue
    }
}
Now, we can create a new snapshot backup of the volume before we resize it. Let’s also give the new snapshot a description. Remember to wait until the snapshot completes before we try to resize it.
$Snapshot = New-EC2Snapshot -VolumeId $TargetVolume.VolumeId -Description "$(get-date -f o). Snapshot before extending volume: $($TargetVolume.VolumeId) on Instance:$($Attachment.InstanceId)"
While ($Snapshot.Status -ne 'completed')
{
$Snapshot = Get-EC2Snapshot -SnapshotId $Snapshot.SnapshotId; Start-Sleep -Seconds 15
}
Next, we extend the current volume.
 Edit-EC2Volume -VolumeId $TargetVolume.VolumeId  -Size $NewSize
The script is complete, but we are not quite done yet. The EBS volume has been resized, but the Windows partition has not. See Figure 4-6 for a visualization. To extend the partition, log into Windows and start the Computer Management MMC. On the Disk Management page, right-click the partition and select Extend Volume. Accept the defaults to extend it to its maximum size.
../images/319650_2_En_4_Chapter/319650_2_En_4_Fig6_HTML.jpg
Figure 4-6

Extending the partition

Optionally we can run the following script on the instance to scan for a volume partition that has a drive letter. It extends the first matching partition with all available unused space.
Foreach ($Partition in $(Get-Partition | Where-Object {$_.Driveletter -ne $Null}))
{Update-Disk -Number $Partition.Disknumber
$maxSize = $((Get-PartitionSupportedSize -DiskNumber $Partition.Disknumber -PartitionNumber $Partition.PartitionNumber).sizeMax)
If ($Partition.Size -lt $maxSize){Resize-Partition -DiskNumber $Partition.Disknumber -PartitionNumber $Partition.PartitionNumber -Size $maxSize;break}}
Finally, we can delete the snapshot if all goes well.
Remove-EC2Snapshot -SnapshotId $Snapshot.SnapshotId -Force

In this exercise we resized a volume while taking a snapshot as a backup for safety. In the next exercise, we will create a script to back up all the volumes in our account on a schedule.

Exercise 4.2: Creating a Backup Agent

AWS gives us the tools to back up and recover a volume on demand, but we really need scheduled backups and the ability to delete snapshots after a specified retention period. Let’s create a script that will back up every volume in a region for our AWS account.

Note that this backup agent script will run from an instance. To perform the activities in this exercise, the instance must be configured with the AdminRole IAM role we created in Chapter 2.

Our script will take three parameters: a type parameter used to differentiate backup sets, RetentionDays for the number of days to keep the backups, and the region to perform the backups. These parameters allow us to run multiple instances of the script with different configurations. For example, the following parameters indicate to run a daily backup retained for two weeks and a weekly backup retained for 90 days.
param(
    [parameter(mandatory=$false)][string]$Type = 'Daily',
    [parameter(mandatory=$false)][string]$RetentionDays = 14,
    [parameter(mandatory=$false)][string]$Region = "us-east-1"
)

The first thing we need to do is determine which volumes to back up. We may not want every volume backed up. For example, we don’t want to back up our SQL data files. We only want to create a snapshot of the volume that contains the SQL backup files.

Let’s use a tag to determine which volumes should be backed up. We will create a new tag, named “BackupEnabled”. We prefer to back up all volumes by default; therefore, the first part of the script will look for any volumes that have not been tagged. If it finds any, it will assume they should be backed up, and set the BackupEnabled tag to true. If we don’t want a volume backed up, just change the tag value to “false”.

Unfortunately, we can only use a filter to find items that have been tagged. We cannot use a filter to find items that have not been tagged. Therefore, we need to get all instances and loop over them and check for the tag. If it does not exist, we add it using the New-EC2Tag we learned about in the last chapter.
# First, find any new volumes that have not been marked for backup
Set-DefaultAWSRegion -region $Region
Get-EC2Volume | ForEach-Object {
    $HasKey = $False
    $_.Tag | ForEach-Object { If ($_.Key -eq 'BackupEnabled') { $HasKey = $True } }
    If ($HasKey -eq $False) {
        # Add Tag to this volume
        $VolumeId = $_.VolumeId
        $Tag = New-Object amazon.EC2.Model.Tag
        $Tag.Key='BackupEnabled'
        $Tag.Value='true'
        Write-Host "Found new volume: $VolumeId"
        New-EC2Tag -ResourceId $VolumeId -Tag $Tag }
}
Now that our volumes are tagged, we can use a filter to find all the volumes that need to be backed up. We can then loop over the volumes and take a snapshot.
$Filter = New-Object Amazon.EC2.Model.Filter
$Filter.Name = 'tag:BackupEnabled'
$Filter.Value = 'True'
Get-EC2Volume -Filter $Filter | ForEach-Object {
#Backup routine goes here
}
If there is a disaster, we may not be able to access the metadata about which snapshot came from which instance. Therefore, if the volume is currently attached to an instance, we should record the name and attachment information in the snapshot description. The following code uses the Get-EC2Instance command we learned about in the last chapter to get information about the instance.
# Backup Routine
If ($_.state -eq "in-use"){
$Device = $_.Attachment[0].Device
$InstanceId = $_.Attachment[0].InstanceId
$Reservation = Get-EC2Instance $InstanceId
$Instance = $Reservation.RunningInstance | Where-Object {$_.InstanceId -eq $InstanceId}
$Name = ($Instance.Tag | Where-Object { $_.Key -eq 'Name' }).Value
$Description = "Attached to InstanceID $InstanceId with Name '$Name' as $Device;" }
Else{$Description = "Unattached to Instance"}
$Volume = $_.VolumeId
Write-Host "Creating snapshot of volume: $Volume; $Description"
$Snapshot = New-EC2Snapshot $Volume -Description "$Type backup of volume $Volume; $Description"
We should also tag the snapshots, so we know which were created by our script. We don’t want our script to delete snapshots it didn’t create. For example, if a developer takes a snapshot before rolling out a new version of an application, they may not want that to be deleted after two weeks. Let’s add a tag called “BackupType” used to differentiate scheduled backups from any others.
# Add a tag so we can distinguish this snapshot from all the others
$Tag = New-Object amazon.EC2.Model.Tag
$Tag.Key='BackupType'
$Tag.Value=$Type
New-EC2Tag -ResourceId $Snapshot.SnapshotID -Tag $Tag
Great! The routine to create a snapshot is done. Now we just have to create a routine to delete old backups after the retention period expires. In this routine, we find all of the snapshots that were created by the backup agent, using the BackupType tag. Then, check how old it is. If it is older than the retention period, the snapshot is deleted.
# Retention routine. Delete any snapshots created by this tool that are older than the specified number of days
$Filter = New-Object Amazon.EC2.Model.Filter
$Filter.Name = 'tag:BackupType'
$Filter.Value = $Type
$RetentionDate = ([DateTime]::Now).AddDays(-$RetentionDays)
Get-EC2Snapshot -Filter $filter |
Where-Object { [datetime]::Parse($_.StartTime) -lt $RetentionDate} |
ForEach-Object { $SnapshotId = $_.SnapshotId
Write-Host "Removing snapshot: $SnapshotId"
Remove-EC2Snapshot -SnapshotId $SnapshotId -Force }

At this point all we must do is schedule the script to run once a day. We have this script deployed on an AWS instance, and it’s saved as C:AWSDailyBackup.ps1.

To schedule the job, log into the instance that is going to run the script and open task scheduler. Then follow these steps:

  1. 1.

    Click the Create a Basic Task link.

     
  2. 2.

    Name the task “DailyBackup” and click Next.

     
  3. 3.

    Choose Daily and click Next.

     
  4. 4.

    Pick a time of day for the script to run and click Next.

     
  5. 5.

    Choose Start a Program and click Next.

     
  6. 6.
    Fill in the next screen, as shown in Figure 4-7, and click Next.
    ../images/319650_2_En_4_Chapter/319650_2_En_4_Fig7_HTML.jpg
    Figure 4-7

    Configure a scheduled task

     
  1. 7.

    Check the “open the properties dialog for this task when I click Finish” option and click Finish.

     
  2. 8.

    Click the Change User or Group... button.

     
  3. 9.
    Change the user to NETWORK SERVICE, as shown in Figure 4-8, and click OK.
    ../images/319650_2_En_4_Chapter/319650_2_En_4_Fig8_HTML.jpg
    Figure 4-8

    Configure User or Group

     
  1. 10.

    Click OK to close the wizard.

     

In this exercise we created a scheduled task that uses snapshots to create a backup of all volumes in a region. Let’s stop and reflect on how easy that was. A few lines of code just replaced backup tapes forever. We don’t need an operator on staff after hours to put tapes in servers. We don’t need to manage tape storage and rotation. If we added a call to Copy-EC2Snapshot targeting another region, we would never have to ship tapes to an offsite storage location again.

Summary

In this chapter, we examined volumes and snapshots. We learned how to customize and add additional volumes at launch as well as modify volumes after launch. We learned how to back up and restore a volume using highly durable snapshots and copy snapshots to another region for even greater durability. In the first example, we created a script to resize a volume. We can use this script anytime we are running out of space in an existing instance. In the second example, we created a scheduled task that backs up all the volumes for a region in our account. We can use this script to replace tape backups.

In the next chapter, we will learn how to configure a Virtual Private Cloud (VPC). VPC allows us to create your own private network configuration in the cloud. We will discuss subnets, routing, and security.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset