VirtualBox上の仮想マシンをVM Importを使って移行する

VirtualBoxから仮想マシンをエクスポートしてEC2へ移行してみました。
2021.04.29

VM Importの機能を検証する際、VirtualBoxの仮想マシンからAMIを作成してEC2で起動してみました。今回はAMIから起動したEC2に接続するところまでをゴールとします。

AMI作成までのイメージはこんな感じです。

前提

  • VirtualBoxをインストールしていること
  • ※VM importの前提条件を満たしていること
    • サポート対象のOSか
    • VM importするファイル形式がサポートされている形式か
  • AWS CLIが利用できること

※詳細な要件については以下ドキュメントを参照下さい。

VM Import/Export の要件 - VM Import/Export

手順

以下の手順で実施していきます。

  • VirtualBoxで仮想マシンの用意
  • 移行対象の仮想マシンをエクスポート
  • VM import用IAMユーザーの作成
  • VM importsサービスロール の作成
  • OVAファイルのアップロード
  • VM をインポート
  • AMIからEC2起動

今回使用した動作環境は以下のとおりです。

  • macOS Catalina 10.15.7
  • VirtualBox6.1.20
  • aws-cli/2.1.30

VirtualBoxで仮想マシンの用意

今回はCentOS8をこちらの記事を参考にVirtualBox上で用意しました。利用したい仮想マシンをお好みで用意しましょう。

移行対象の仮想マシンをエクスポート

エクスポートする前に、以下の必要な設定を確認しておきましょう。

VM エクスポートに必要な設定

VirtualBoxを開いて仮想アプライアンスエクスポートをクリックします。

エクスポートしたい仮想マシンの選択画面となるので、今回はVM Importに使用したい「vmimport-test-centps8」をエクスポートします。

エクスポート先などが指定できますのでお好みで変更して下さい。今回はデフォルトのまま進めていきます。

次の画面では詳細情報としてバージョンなどを編集することができます。今回は検証なので特に指定せずにエクスポートしていきます。

しばらくすると、エクスポート先にOVA形式でファイルが作成されます。これで仮想マシンのエクスポートは完了です。

S3バケットの作成

仮想マシンのディスクイメージ(OVAファイル)をアップロードする先となるS3バケットを作成しましょう。これは既存のバケット でも問題ありません。今回は「vm-import-test-bucket」というバケット名で進めていきます。

VM import用IAMユーザーの作成

次にVM Import用のIAMユーザーを作成していきます。今回はAWS CLIで使用するため、コンソールへの認証情報はなくても大丈夫です。ポリシーはドキュメント通り以下のように設定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListAllMyBuckets"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:CreateBucket",
        "s3:DeleteBucket",
        "s3:DeleteObject",
        "s3:GetBucketLocation",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:PutObject"
      ],
      "Resource": ["arn:aws:s3:::vm-import-test-bucket","arn:aws:s3:::vm-import-test-bucket/*"]
    },
    {
      "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": "*"
    }
  ]
}

この権限はイメージのインポート以外にもインスタンスのインポートなどにも使用する前提のため、少し幅広い権限が許可されています。必要に応じて不要な権限は絞って下さい。

IAMユーザーの作成が完了したら、AWS CLIにアクセスキー とシークレットアクセスキー を設定しましょう。今回は「vmimport-user」というプロファイル名で進めていきます。

VM importsサービスロール の作成

次にAMIを作成するためのサービスロールをAWS CLIから作成していきます。(コンソールから作成しても問題ありません)本手順は先ほど作成したVM import用IAMユーザーではなく、ロールを作成できる権限を持ったユーザーで実行して下さい。

ローカルにtrust-policy.jsonという名前のファイルで以下のポリシーを定義します。

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": { "Service": "vmie.amazonaws.com" },
         "Action": "sts:AssumeRole",
         "Condition": {
            "StringEquals":{
               "sts:Externalid": "vmimport"
            }
         }
      }
   ]
}

create-role コマンドを使用して、vmimport という名前のロールを作成してそのロールへのアクセス権を VM Import/Export に付与します。前の手順で作成した trust-policy.json ファイルの場所への絶対パスを指定してください。

aws iam create-role --role-name vmimport --assume-role-policy-document "file://trust-policy.json"

次にrole-policy.jsonという名前のファイルを作成します。vm-import-test-bucketの部分は自分で作成したS3バケット名に置き換えて下さい。

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "s3:ListBucket",
            "s3:GetBucketLocation"
         ],
         "Resource": [
            "arn:aws:s3:::vm-import-test-bucket"
         ]
      },
      {
         "Effect": "Allow",
         "Action": [
            "s3:GetObject"
         ],
         "Resource": [
            "arn:aws:s3:::vm-import-test-bucket/*"
         ]
      },
      {
         "Effect": "Allow",
         "Action":[
            "ec2:ModifySnapshotAttribute",
            "ec2:CopySnapshot",
            "ec2:RegisterImage",
            "ec2:Describe*"
         ],
         "Resource": "*"
      }
   ]
}

次のput-role-policyコマンドを使用して、上記で作成したロールにポリシーをアタッチします。

aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document "file://role-policy.json"

OVAファイルのアップロード

S3にVirtualBoxからエクスポートしたOVAファイルをアップロードします。コンソールでもCLIでもどちらから実行して頂いても大丈夫です。CLIから実施する場合は、vmimport-test-centos8.ovaにはエクスポートしたOVAファイル名、vm-import-test-bucketにはS3バケット名を適宜置き換えて下さい。

aws s3 cp --profile vmimport-user vmimport-test-centos8.ova s3://vm-import-test-bucket/

VM をインポート

ここから実際にインポートしてAMIを作成していきます。import-imageを実行して、インポートタスクを作成、そのタスクからサービスロール がOVAファイルの取得からAMIとEBSスナップショットの作成を実行してくれます。

インポートを実行する前に、containers.jsonというファイルを以下の定義で作成します。

[
  {
    "Description": "My Original CentOS8",
    "Format": "ova",
    "UserBucket": {
        "S3Bucket": "vm-import-test-bucket",
        "S3Key": "vmimport-test-centos8.ova"
    }
  }
]

import-imageを実行して、インポートタスクを作成します。以下のようにレスポンスがすぐ返ってきますが、ここから完了するまで少し待ちましょう。ここで先ほど作成したサービスロールがcontainers.jsonの情報からAMIを作成してくれています。

$ aws ec2 import-image --profile vmimport --description "My CentOS8 OVA" --disk-containers file://containers.json
{
    "Description": "My CentOS8 OVA",
    "ImportTaskId": "import-ami-023fc7d5c002329eb",
    "Progress": "1",
    "SnapshotDetails": [
        {
            "Description": "My Original CentOS8",
            "DiskImageSize": 0.0,
            "Format": "OVA",
            "UserBucket": {
                "S3Bucket": "vm-import-test-bucket",
                "S3Key": "vmimport-test-centos8.ova"
            }
        }
    ],
    "Status": "active",
    "StatusMessage": "pending"
}

進捗状況を確認するには以下のコマンドを実行します。--import-task-idsの値はインポートタスク作成時のImportTaskIdを指定しましょう。

aws ec2 describe-import-image-tasks --profile vmimport-user --import-task-ids import-ami-023fc7d5c002329eb

こんな感じにプロセスが進んでいることを確認することができます。

{
    "ImportImageTasks": [
        {
            "Description": "My CentOS8 OVA",
            "ImportTaskId": "import-ami-023fc7d5c002329eb",
            "Progress": "27",
            "SnapshotDetails": [
                {
                    "DeviceName": "/dev/sdf",
                    "DiskImageSize": 870063104.0,
                    "Format": "VMDK",
                    "Status": "completed",
                    "UserBucket": {
                        "S3Bucket": "vm-import-test-bucket",
                        "S3Key": "vmimport-test-centos8.ova"
                    }
                }
            ],
            "Status": "active",
            "StatusMessage": "updating",
            "Tags": []
        }
    ]
}

完了するとStatuscompletedになります。

"ImportImageTasks": [
        {
            "Architecture": "x86_64",
            "Description": "My CentOS8 OVA",
            "ImageId": "ami-04a7c553597460b02",
            "ImportTaskId": "import-ami-023fc7d5c002329eb",
            "Platform": "Linux",
            "SnapshotDetails": [
                {
                    "DeviceName": "/dev/sda1",
                    "DiskImageSize": 870063104.0,
                    "Format": "VMDK",
                    "SnapshotId": "snap-074407c0d7f2b157b",
                    "Status": "completed",
                    "UserBucket": {
                        "S3Bucket": "vm-import-test-bucket",
                        "S3Key": "vmimport-test-centos8.ova"
                    }
                }
            ],
            "Status": "completed",
            "Tags": []
        }
    ]
}

AMIを確認してみると、問題なく作成されていることを確認することができました。

EBSスナップショットも作成されていました。

AMIからEC2起動

AMIまで作成できれば、あとは通常のEC2の起動と同じように扱うことができます。

AMIからEC2を起動してSSM接続も問題なくできました。

まとめ

VirtualBoxからエクスポートしたOVAファイルからVM Importを試してみました。途中自分でサービスロールを作成する必要はありますが、比較的手軽にインポートすることができました。VMをEC2上で動かしたい方はぜひ試してみて下さい。