LightsailからEC2への移行をTerminalで完結させてみた #reinvent

re:Inventで発表された、LightsailからEC2への移行をTerminalで完結させてみました。
2018.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本日の速報にて「Amazon Lightsail が EC2 に移行できるようになりました! #reinvent」という記事が上がりました。読んでいて個人的に気になったのは、「この移行手続きをTerminalで完結させる場合、どれくらいの手数になるんだろうか」という1点でした。早速試してみました。

目次

Terminalからのlightsail手続きに必要な要素

AWS管理コンソールが補完してくれていた項目を全て賄う必要があります。

今回は以下の2つです。

  • blueprint_id
  • bundle_id

正直見慣れない項目でしたが、過去にDevelopersIOにて記事として上がっていました。参考にしながら項目を取得します。

手順は以下の通りです。

  1. Lightsailインスタンスの作成
  2. Lightsailスナップショットの作成
  3. Lightsailスナップショットのエクスポート
  4. エクスポートしたイメージを元にEC2インスタンスの作成

blueprint_idの確認

上の記事を見てみるとわかりますが、当時のステータスにはblueprint_idが含まれていません。そこで念の為確認してみます。

% aws lightsail --region ap-northeast-1 get-blueprints
{
    "blueprints": [
        {
            "blueprintId": "windows_server_2016_2018_10_14",
            "name": "Windows Server 2016",
            "group": "windows_2016",
            "type": "os",
            "description": "Amazon Lightsail helps you build, deploy, scale, and manage Microsoft applications quickly, easily, and cost effectively with Windows Server 2016. For business IT applications, Lightsail runs Windows-based solutions in a secure, easily managed, and performant cloud environment. For Microsoft developers, Windows Server on Lightsail provides a flexible and agile development platform, integrated with .NET to help accelerate development cycles.",
            "isActive": true,
            "minPower": 0,
            "version": "2018.10.14",
            "versionCode": "1",
            "productUrl": "https://aws.amazon.com/marketplace/pp/B01M7SJEU7",
            "licenseUrl": "https://d7umqicpi7263.cloudfront.net/eula/product/13c2dbc9-57fc-4958-922e-a1ba7e223b0d/fdfd055c-b2ff-4c64-a699-504da826ccd4.txt",
            "platform": "WINDOWS"
        },
...

blueprintIdが含まれていることを確認できました。そこで今度はblueprintIdに絞ってみます。

% aws lightsail --region ap-northeast-1 get-blueprints | jq '.blueprints[].blueprintId'
"windows_server_2016_2018_10_14"
"windows_server_2012_2018_10_14"
"windows_server_2016_sql_2016_express_2018_10_14"
"amazon_linux_2018_03_0_2"
"ubuntu_16_04_2"
"ubuntu_18_04"
"debian_8_7"
"debian_9_5"
"freebsd_11_1"
"opensuse_42_2"
"centos_7_1805_01"
"wordpress_4_9_8"
"wordpress_multisite_4_9_8"
"lamp_5_6_37_2"
"lamp_7_1_20_1"
"nodejs_10_8_0"
"joomla_3_8_11"
"magento_2_2_5"
"mean_4_0_1"
"drupal_8_5_6"
"gitlab_11_1_4_1"
"redmine_3_4_6"
"nginx_1_14_0_1"
"plesk_ubuntu_17_8_11_1"

ここから選択します。

bundle_idの確認

次にbundle_idを確認してみます。blueprint_idと同じ手続きを取ってみます。

% aws lightsail --region ap-northeast-1 get-bundles
{
    "bundles": [
        {
            "price": 3.5,
            "cpuCount": 1,
            "diskSizeInGb": 20,
            "bundleId": "nano_2_0",
            "instanceType": "nano",
            "isActive": true,
            "name": "Nano",
            "power": 300,
            "ramSizeInGb": 0.5,
            "transferPerMonthInGb": 1024,
            "supportedPlatforms": [
                "LINUX_UNIX"
            ]
        },
...

bundleIdが含まれていることを確認できました。同じくbundleIdに絞ってみます。

% aws lightsail --region ap-northeast-1 get-blueprints | jq '.bundles[].bundleId'
"nano_2_0"
"micro_2_0"
"small_2_0"
"medium_2_0"
"large_2_0"
"xlarge_2_0"
"2xlarge_2_0"
"nano_win_2_0"
"micro_win_2_0"
"small_win_2_0"
"medium_win_2_0"
"large_win_2_0"
"xlarge_win_2_0"
"2xlarge_win_2_0"

同じく、ここから選択します。

Lighttailインスタンスの作成

今回はblueprint_idamazon_linux_2018_03_0_2bundle_idnano_2_0を選択しました。

% aws lightsail create-instances --instance-name="test" --availability-zone=ap-northeast-1a --blueprint-id="amazon_linux_2018_03_0_2" --bundle-id="nano_2_0"
{
    "operations": [
        {
            "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "resourceName": "test",
            "resourceType": "Instance",
            "createdAt": 1543498782.003,
            "location": {
                "availabilityZone": "ap-northeast-1a",
                "regionName": "ap-northeast-1"
            },
            "isTerminal": false,
            "operationType": "CreateInstance",
            "status": "Started",
            "statusChangedAt": 1543498782.003
        }
    ]
}

スナップショットの作成

スナップショットを作成します。インスタンス名とスナップショット名が必要です。

% aws lightsail create-instance-snapshot --instance-name="test" --instance-snapshot-name="test-snap"
{
    "operations": [
        {
            "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "resourceName": "test-snap",
            "resourceType": "InstanceSnapshot",
            "createdAt": 1543500234.107,
            "location": {
                "availabilityZone": "all",
                "regionName": "ap-northeast-1"
            },
            "isTerminal": false,
            "operationDetails": "test",
            "operationType": "CreateInstanceSnapshot",
            "status": "Started",
            "statusChangedAt": 1543500234.107
        },
        {
            "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "resourceName": "test",
            "resourceType": "Instance",
            "createdAt": 1543500234.107,
            "location": {
                "availabilityZone": "ap-northeast-1a",
                "regionName": "ap-northeast-1"
            },
            "isTerminal": false,
            "operationDetails": "test-snap",
            "operationType": "CreateInstanceSnapshot",
            "status": "Started",
            "statusChangedAt": 1543500234.107
        }
    ]
}

snapshotのexport

exportするスナップショット名を指定します。

% aws lightsail export-snapshot --source-snapshot-name="test-snap"
{
    "operations": [
        {
            "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "resourceName": "test-snap",
            "resourceType": "InstanceSnapshot",
            "createdAt": 1543500491.587,
            "location": {
                "availabilityZone": "all",
                "regionName": "ap-northeast-1"
            },
            "isTerminal": false,
            "operationDetails": "ExportSnapshotRecord-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "operationType": "ExportSnapshot",
            "status": "Started",
            "statusChangedAt": 1543500491.587
        },
        {
            "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "resourceName": "ExportSnapshotRecord-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "resourceType": "ExportSnapshotRecord",
            "createdAt": 1543500491.587,
            "location": {
                "availabilityZone": "all",
                "regionName": "ap-northeast-1"
            },
            "isTerminal": false,
            "operationDetails": "test-snap",
            "operationType": "ExportSnapshot",
            "status": "Started",
            "statusChangedAt": 1543500491.587
        }
    ]
}

export状態についてはget-export-snapshot-recordsで確認可能です。

% lightsail get-export-snapshot-records
{
    "exportSnapshotRecords": [
        {
            "name": "ExportSnapshotRecord-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "arn": "arn:aws:lightsail:ap-northeast-1:XXXXXXXXXXXX:ExportSnapshotRecord/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "createdAt": 1543500491.587,
            "location": {
                "availabilityZone": "all",
                "regionName": "ap-northeast-1"
            },
            "resourceType": "ExportSnapshotRecord",
            "state": "Started",
            "sourceInfo": {
                "resourceType": "InstanceSnapshot",
                "createdAt": 1543500234.107,
                "name": "test-snap",
                "arn": "arn:aws:lightsail:ap-northeast-1:XXXXXXXXXXXX:InstanceSnapshot/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
                "fromResourceName": "test",
                "fromResourceArn": "arn:aws:lightsail:ap-northeast-1:XXXXXXXXXXXX:Instance/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
                "instanceSnapshotInfo": {
                    "fromBundleId": "nano_2_0",
                    "fromBlueprintId": "amazon_linux_2018_03_0_2",
                    "fromDiskInfo": [
                        {
                            "path": "/dev/xvda",
                            "sizeInGb": 20,
                            "isSystemDisk": true
                        }
                    ]
                }
            },
            "destinationInfo": {
                "id": "",
                "service": "Aws::EC2::Image"
            }
        }
    ]
}

Export完了時

完了するとexportSnapshotRecords.stateSucceededに変わり、exportSnapshotRecords.destinationInfo.idに値が設定されます。

{
    "exportSnapshotRecords": [
        {
            "name": "ExportSnapshotRecord-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "arn": "arn:aws:lightsail:ap-northeast-1:XXXXXXXXXXXX:ExportSnapshotRecord/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "createdAt": 1543500491.587,
            "location": {
                "availabilityZone": "all",
                "regionName": "ap-northeast-1"
            },
            "resourceType": "ExportSnapshotRecord",
            "state": "Succeeded",
            "sourceInfo": {
                "resourceType": "InstanceSnapshot",
                "createdAt": 1543500234.107,
                "name": "test-snap",
                "arn": "arn:aws:lightsail:ap-northeast-1:XXXXXXXXXXXX:InstanceSnapshot/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
                "fromResourceName": "test",
                "fromResourceArn": "arn:aws:lightsail:ap-northeast-1:XXXXXXXXXXXX:Instance/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
                "instanceSnapshotInfo": {
                    "fromBundleId": "nano_2_0",
                    "fromBlueprintId": "amazon_linux_2018_03_0_2",
                    "fromDiskInfo": [
                        {
                            "path": "/dev/xvda",
                            "sizeInGb": 20,
                            "isSystemDisk": true
                        }
                    ]
                }
            },
            "destinationInfo": {
                "id": "ami-XXXXXXXXXXXXXXXX",
                "service": "Aws::EC2::Image"
            }
        }
    ]
}

EC2の起動

Exportしたイメージを元に起動します。起動時にはimage_idが必要となりますが、全件検索すると時間が非常にかかるため、イメージ名を元にして絞り込みます。

% aws ec2 describe-images --filters Name=name,Values=test-snap
{
    "Images": [
        {
            "Architecture": "x86_64",
            "CreationDate": "2018-11-29T14:08:29.000Z",
            "ImageId": "ami-XXXXXXXXXXXXXXXX",
            "ImageLocation": "XXXXXXXXXXXX/test-snap",
            "ImageType": "machine",
            "Public": false,
            "OwnerId": "XXXXXXXXXXXX",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/xvda",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-XXXXXXXXXXXXXXXX",
                        "VolumeSize": 20,
                        "VolumeType": "gp2",
                        "Encrypted": true
                    }
                }
            ],
            "Description": "An instance snapshot exported from Amazon Lightsail.",
            "EnaSupport": true,
            "Hypervisor": "xen",
            "Name": "test-snap",
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SriovNetSupport": "simple",
            "VirtualizationType": "hvm"
        }
    ]
}

確認できたimageIdを元に起動します。lightsailで指定したbundleに合わせて、instanceTypeはt2_nanoを指定しています。

% aws ec2 run-instances --image-id="ami-XXXXXXXXXXXXXXXX" --instance-type="t2.nano"
{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-XXXXXXXXXXXXXXXX",
            "InstanceId": "i-XXXXXXXXXXXXXXXX",
            "InstanceType": "t2.nano",
            "LaunchTime": "2018-11-29T14:50:25.000Z",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "ap-northeast-1a",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-XX-XX-XX-XX.ap-northeast-1.compute.internal",
            "PrivateIpAddress": "XX.XX.XX.XX",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "StateTransitionReason": "",
            "SubnetId": "subnet-XXXXXXXX",
            "VpcId": "vpc-XXXXXXXX",
            "Architecture": "x86_64",
            "BlockDeviceMappings": [],
            "ClientToken": "",
            "EbsOptimized": false,
            "Hypervisor": "xen",
            "NetworkInterfaces": [
                {
                    "Attachment": {
                        "AttachTime": "2018-11-29T14:50:25.000Z",
                        "AttachmentId": "eni-attach-XXXXXXXXXXXXXXXX",
                        "DeleteOnTermination": true,
                        "DeviceIndex": 0,
                        "Status": "attaching"
                    },
                    "Description": "",
                    "Groups": [
                        {
                            "GroupName": "default",
                            "GroupId": "sg-XXXXXXXX"
                        }
                    ],
                    "Ipv6Addresses": [],
                    "MacAddress": "XX:XX:XX:XX:XX:XX",
                    "NetworkInterfaceId": "eni-XXXXXXXXXXXXXXXX",
                    "OwnerId": "XXXXXXXXXXXX",
                    "PrivateDnsName": "ip-XX-XX-XX-XX.ap-northeast-1.compute.internal",
                    "PrivateIpAddress": "XX.XX.XX.XX",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateDnsName": "ip-XX-XX-XX-XX.ap-northeast-1.compute.internal",
                            "PrivateIpAddress": "XX.XX.XX.XX"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Status": "in-use",
                    "SubnetId": "subnet-XXXXXXXX",
                    "VpcId": "vpc-XXXXXXXX"
                }
            ],
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SecurityGroups": [
                {
                    "GroupName": "default",
                    "GroupId": "sg-XXXXXXXX"
                }
            ],
            "SourceDestCheck": true,
            "StateReason": {
                "Code": "pending",
                "Message": "pending"
            },
            "VirtualizationType": "hvm",
            "CpuOptions": {
                "CoreCount": 1,
                "ThreadsPerCore": 1
            }
        }
    ],
    "OwnerId": "XXXXXXXXXXXX",
    "ReservationId": "r-XXXXXXXXXXXXXXXX"
}

まとめ

lightsail自体にそれ程時間はかかりませんでした。ec2のコマンドが多すぎて、どれを使うと先に進めるのかの検証に手間が掛かった感じです。

事前にパラメータ等が確定していれば、コマンドを適切な順に設定することで効率化も図れるのではないかと思われます。