ImportImageによるVMインポート


`ImportInstance` ではなく `ImportImage` でVMインポートを行う。
S3にVMイメージが置いてある前提で、S3のイメージから直接AMIとEBSスナップショットを作成する。
ローカルPCに最新の awscli をインストールしておくこと。

VMイメージのエクスポート手順は `ImportInstance` と同じ。
以下、気をつけたこと。前提条件については [VM Import/Export Prerequisites](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html) も参照。

* CentOS4.5 → 5.1～5.11、6.1～6.6、7.0、7.1どれかへのアップグレード
* Grubブートローダー(レガシーバージョンもしくは新しいGrub 2)および、ストックカーネルを使う
* DHCPを有効にする
* iptablesを無効にする
* ルートファイルシステムはext2、ext3、ext4、Btrfs、JFS、XFSのいずれか
* /bootを/とは別のパーティションにし、この両方ともが同じディスクに配置されている
* /etc/sysconfig/network-scripts/ifcfg-eth0 がない場合は作っておく
* /etc/sysconfig/networkに、GATEWAYが書いてある場合はコメントアウトか削除する
* selinuxを無効にしておく
* nfsマウントの無効化(コメントアウト)
* fluentd, ntpdなどネットワークが無いと起動 FAILED するデーモンの停止
* CDドライブ/FDドライブのデバイス削除
* vmware-tools の自動起動を停止

## 前準備

VM Import/Export サービス(vmie.amazonaws.com)が作業時に使う(`AssumeRole`する)ロールを作成する。

### <i class="fa fa-angle-double-right"></i> サービスロールの作成

[VM Import Service Role](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html#vmimport-service-role) を参考に設定。

今回はロール名を `vmimport` とする。デフォルトでこの名前のロールが使われるため。
実行時にパラメータとして指定できるので、他のロール名でも構わない。

適当にロールを作ったらトラストポリシーを下記のように変更する。
`sts:ExternalId` は `vmimport` で固定。

```json:trust-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "vmie.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "vmimport"
        }
      }
    }
  ]
}
```

このロールに対して、下記のようなポリシーを設定する。

```json:access-policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::<disk-image-file-bucket>"
            ]
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::<disk-image-file-bucket>/*"
            ]
        },
        {
            "Sid": "3",
            "Effect": "Allow",
            "Action": [
                "ec2:CopySnapshot",
                "ec2:ModifySnapshotAttribute",
                "ec2:RegisterImage",
                "ec2:Describe*",
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

### <i class="fa fa-angle-double-right"></i> ユーザのポリシー設定

[IAM Permissions](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html#vmimport-iam-permissions) を参考に設定。

作業者のIAMユーザに必要なポリシーを設定する。
今回は `vmie-vmimport` というマネージドポリシーを作成した。

```json:vmie-vmimport
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:DeleteBucket",
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::<disk-image-file-bucket>"
            ]
        },
        {
            "Sid": "3",
            "Effect": "Allow",
            "Action": [
                "s3:DeleteObject",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::<disk-image-file-bucket>/*"
            ]
        },
        {
            "Sid": "4",
            "Effect": "Allow",
            "Action": [
                "ec2:CancelConversionTask",
                "ec2:CancelExportTask",
                "ec2:CreateImage",
                "ec2:CreateInstanceExportTask",
                "ec2:CreateTags",
                "ec2:DeleteTags",
                "ec2:DescribeConversionTasks",
                "ec2:DescribeExportTasks",
                "ec2:DescribeInstanceAttribute",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:DescribeTags",
                "ec2:ImportInstance",
                "ec2:ImportVolume",
                "ec2:StartInstances",
                "ec2:StopInstances",
                "ec2:TerminateInstances",
                "ec2:ImportImage",
                "ec2:ImportSnapshot",
                "ec2:DescribeImportImageTasks",
                "ec2:DescribeImportSnapshotTasks",
                "ec2:CancelImportTask"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

## import-image の実行

### <i class="fa fa-angle-double-right"></i> パラメータ用JSONの作成

雛形はawsコマンドで生成することが出来る。
`aws ec2 import-image --generate-cli-skeleton > params.json`

```json:params.json
{
  "DryRun": true,
  "Description": "",
  "DiskContainers": [
    {
      "Description": "",
      "Format": "",
      "Url": "",
      "UserBucket": {
        "S3Bucket": "",
        "S3Key": ""
      },
      "DeviceName": "",
      "SnapshotId": ""
    }
  ],
  "LicenseType": "",
  "Hypervisor": "",
  "Architecture": "",
  "Platform": "",
  "ClientData": {
    "UploadStart": null,
    "UploadEnd": null,
    "UploadSize": null,
    "Comment": ""
  },
  "ClientToken": "",
  "RoleName": ""
}
```

雛形を元にパラメータを埋めていく。

```json:params.json
{
  "Description": "vm-import",
  "DiskContainers": [
    {
      "UserBucket": {
        "S3Bucket": "<disk-image-file-bucket>",
        "S3Key": "<path/to/vm-image.vmdk>"
      }
    }
  ]
}
```

### <i class="fa fa-angle-double-right"></i> VMイメージのインポート

DryRunフラグを有効にした状態で実行してみる。

`aws ec2 import-image --cli-input-json file://./params.json --dry-run`

問題がなければ下記のようなメッセージが表示される。

> A client error (DryRunOperation) occurred when calling the ImportImage operation: Request would have succeeded, but DryRun flag is set.

DryRunフラグを外して実際にインポート処理を実行する。
コマンドは同じ。

`aws ec2 import-image --cli-input-json file://./params.json`

タスクの作成に成功すると下記のようなメッセージが表示される。

```json
{
    "Status": "active",
    "Description": "vm-import",
    "Progress": "2",
    "SnapshotDetails": [
        {
            "UserBucket": {
                "S3Bucket": "<disk-image-file-bucket>",
                "S3Key": "<path/to/vm-image.vmdk>"
            },
            "DiskImageSize": 0.0
        }
    ],
    "StatusMessage": "pending",
    "ImportTaskId": "import-ami-XXXXXXXX"
}
```

### <i class="fa fa-angle-double-right"></i> インポートタスクの進捗確認

終わるまで待つ。

`aws ec2 describe-import-image-tasks --import-task-ids import-ami-XXXXXXXX`

`StatusMessage` の変化はこんな感じ。

* pending
* validating
* converting
* updating
* preparing to boot
* booting
* booted
* preparing ami
* (気づいたら完了してたので不明・・・)

失敗時の例。FDDが残っていたのでエラーになった。
これだとエラーの詳細が分からないので、AWSサポートにインポートタスクIDを連絡すると詳細を調査してくれる。
今のところ自分で詳細を知る術はないらしい。

```json
{
    "ImportImageTasks": [
        {
            "Status": "active",
            "SnapshotDetails": [
                {
                    "UserBucket": {
                        "S3Bucket": "<disk-image-file-bucket>",
                        "S3Key": "<path/to/vm-image.vmdk>"
                    },
                    "DiskImageSize": 111.....0,
                    "Format": "VMDK"
                }
            ],
            "Description": "vm-import",
            "StatusMessage": "ServerError: an internal error has occurred during conversion.",
            "ImportTaskId": "import-ami-XXXXXXXX"
        }
    ]
}
```

完了！

```json
{
    "ImportImageTasks": [
        {
            "Status": "completed",
            "LicenseType": "BYOL",
            "Description": "vm-import",
            "ImageId": "ami-XXXXXXXX",
            "Platform": "Linux",
            "Architecture": "x86_64",
            "SnapshotDetails": [
                {
                    "UserBucket": {
                        "S3Bucket": "<disk-image-file-bucket>",
                        "S3Key": "<path/to/vm-image.vmdk>"
                    },
                    "SnapshotId": "snap-XXXXXXXX",
                    "DiskImageSize": 111....,
                    "DeviceName": "/dev/sda1",
                    "Format": "VMDK"
                }
            ],
            "ImportTaskId": "import-ami-XXXXXXXX"
        }
    ]
}
```

### <i class="fa fa-angle-double-right"></i> インポート結果の確認

ImportImage の結果 AMI と EBS スナップショットが作成されているはず。
DescribeImportImageTasks のレスポンスにそれぞれの ID が含まれている。

AMI Name にはインポートタスク ID が入る。
EBS スナップショットの description には `Created by AWS-VMImport service for import-ami-XXXXXXX` と入る。