📦

暗号化された AWS Lightsail を ESXi に移行

に公開

はじめに

AWS Lightsail の Ubuntu サーバーを、ローカル ESXi に仮想マシンごと移行する必要がありました。

想定していた流れはシンプルです。

Lightsail スナップショット
  → EC2 AMI に変換
  → VMDK エクスポート
  → ESXi にインポート

ところが、実際にやってみると Lightsail 由来の AMI は EBS が暗号化されている ため、そのままではエクスポートできないという壁にぶつかりました。

この記事では、暗号化の壁をどう越えたのか、ESXi で起動するまでに何にハマったのかをまとめます。


前提環境

項目 内容
AWS 側 Lightsail Ubuntu 22.04 → EC2 AMI に変換済み
ローカル側 ESXi(無償版)
作業マシン AWS CLI v2 インストール済み
ブートモード UEFI(EFI)

Lightsail のスナップショットから EC2 AMI を作成するところまでは、AWS コンソールの「Lightsail → EC2 にエクスポート」機能でできます。ここまでは特に問題ありません。


ステップ 1: IAM ロール vmimport の準備

AWS の VM Import/Export を使うには、vmimport という名前の IAM ロールが必要です。このロールがないとエクスポートコマンドが失敗します。

まず、信頼ポリシーを作成します。

trust-policy.json:

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

ロールを作成します。

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

次に、S3 と EC2 へのアクセス権限を付与するポリシーを作成します。<your-bucket> はエクスポート先の S3 バケット名に置き換えてください。

role-policy.json:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:PutObject",
        "s3:GetBucketAcl"
      ],
      "Resource": [
        "arn:aws:s3:::<your-bucket>",
        "arn:aws:s3:::<your-bucket>/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:ModifySnapshotAttribute",
        "ec2:CopySnapshot",
        "ec2:RegisterImage",
        "ec2:Describe*"
      ],
      "Resource": "*"
    }
  ]
}
aws iam put-role-policy \
  --role-name vmimport \
  --policy-name vmimport \
  --policy-document file://role-policy.json

ステップ 2: 暗号化の壁 — エクスポートできない

IAM ロールを用意し、S3 バケットも作りましたが、いざエクスポートしようとすると、こうなりました。

aws ec2 export-image \
  --image-id ami-xxxxxxxxxxxxxxxxx \
  --disk-image-format VMDK \
  --s3-export-location S3Bucket=<your-bucket>,S3Prefix=exports/
An error occurred (InvalidParameter) when calling the ExportImage operation:
The image has encrypted EBS block devices and is not supported for export.

Lightsail から EC2 に変換した AMI は、EBS スナップショットが暗号化されています。 これは Lightsail 側の仕様です。

「じゃあ暗号化を外せばいいのでは」と思って、スナップショットをコピーする際に --no-encrypted を試しました。

aws ec2 copy-snapshot \
  --source-region ap-northeast-1 \
  --source-snapshot-id snap-xxxxxxxxxxxxxxxxx \
  --no-encrypted

結果:効きません。 --no-encrypted は「暗号化しない」という指定であって、「暗号化を解除する」という意味ではありません。暗号化済みスナップショットからコピーする場合、コピー先も必ず暗号化されます。

解決策: rsync で非暗号化ディスクにデータをコピーする

ブロックレベルでの暗号化解除ができない以上、ファイルレベルでコピーするしかないと判断しました。

通常ルート(不可):
  暗号化 AMI ──→ export-image ──→ ✗ エラー

実際のルート:
  暗号化 AMI ──→ インスタンス起動
                    ├── /dev/nvme0n1  暗号化 EBS(元)
                    └── /dev/nvme1n1  非暗号化 EBS(新)

                      rsync / dd でコピー

                 非暗号化 AMI 作成 ──→ export-image ──→ ✓ VMDK

つまり:

  1. 暗号化 AMI からインスタンスを起動する
  2. 非暗号化の空 EBS ボリュームを追加でアタッチする
  3. rsync でファイルシステムの中身を丸ごとコピーする
  4. 非暗号化ディスクから新しい AMI を作成する

この方式なら、ファイルシステムの中身は同一で、ストレージの暗号化だけ外れた AMI が手に入ります。


ステップ 3: rsync による非暗号化ディスク作成

ここが一番手数が多いステップです。暗号化 AMI からインスタンスを起動し、非暗号化 EBS を追加して、ファイルシステムを丸ごとコピーします。

3-1. インスタンスの起動と EBS 追加

暗号化 AMI からインスタンスを起動します。

起動したら、AWS コンソールまたは CLI で非暗号化の EBS ボリュームを作成し、インスタンスにアタッチします。元のディスクと同じかそれ以上のサイズにしてください。

# 非暗号化 EBS ボリュームを作成(例: 40GB, gp3)
aws ec2 create-volume \
  --availability-zone ap-northeast-1a \
  --size 40 \
  --volume-type gp3 \
  --no-encrypted

# インスタンスにアタッチ
aws ec2 attach-volume \
  --volume-id vol-xxxxxxxxxxxxxxxxx \
  --instance-id i-xxxxxxxxxxxxxxxxx \
  --device /dev/sdf

3-2. 新ディスクのパーティショニング

SSH でインスタンスにログインし、新しいディスクを準備します。UEFI ブートに必要な EFI パーティションと、ルートパーティションを作成します。

# 新しいディスクを確認(/dev/nvme1n1 等。環境によってデバイス名は異なる)
lsblk

# パーティションテーブル作成
sudo parted /dev/nvme1n1 --script mklabel gpt

# EFI パーティション(200MiB)
sudo parted /dev/nvme1n1 --script mkpart primary fat32 1MiB 201MiB
sudo parted /dev/nvme1n1 --script set 1 esp on

# ルートパーティション(残り全部)
sudo parted /dev/nvme1n1 --script mkpart primary ext4 201MiB 100%

# フォーマット
sudo mkfs.vfat -F 32 /dev/nvme1n1p1
sudo mkfs.ext4 /dev/nvme1n1p2

3-3. rsync でコピー

新しいディスクのルートパーティションをマウントし、rsync でファイルシステムをコピーします。

# 新ディスクをマウント
sudo mkdir -p /mnt/newroot
sudo mount /dev/nvme1n1p2 /mnt/newroot

# EFI パーティションもマウント
sudo mkdir -p /mnt/newroot/boot/efi
sudo mount /dev/nvme1n1p1 /mnt/newroot/boot/efi

# rsync でコピー(除外リスト付き)
sudo rsync -axHAWXS --numeric-ids --info=progress2 \
  --exclude='/dev/*' \
  --exclude='/proc/*' \
  --exclude='/sys/*' \
  --exclude='/tmp/*' \
  --exclude='/run/*' \
  --exclude='/mnt/*' \
  --exclude='/media/*' \
  --exclude='/lost+found' \
  / /mnt/newroot/

3-4. /etc/fstab の UUID 更新

新しいパーティションは UUID が変わっているので、fstab を書き換えます。

# 新しい UUID を確認
sudo blkid /dev/nvme1n1p1  # EFI パーティション
sudo blkid /dev/nvme1n1p2  # ルートパーティション

# fstab を編集
sudo nano /mnt/newroot/etc/fstab

fstab の中身を、新しい UUID に書き換えます。

# 例
UUID=xxxx-xxxx  /boot/efi  vfat  umask=0077  0  1
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /  ext4  defaults  0  1

3-5. GRUB の再インストール

新しいディスクにブートローダーをインストールします。chroot 環境で作業します。

# 必要なファイルシステムをバインドマウント
sudo mount --bind /dev  /mnt/newroot/dev
sudo mount --bind /dev/pts /mnt/newroot/dev/pts
sudo mount --bind /proc /mnt/newroot/proc
sudo mount --bind /sys  /mnt/newroot/sys
sudo mount --bind /sys/firmware/efi/efivars /mnt/newroot/sys/firmware/efi/efivars 2>/dev/null || true

# chroot
sudo chroot /mnt/newroot

# GRUB をインストール
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck

# initramfs を更新
update-initramfs -u -k all

# GRUB 設定を更新
update-grub

3-6. EFI フォールバック配置

ESXi のような環境では EFI のブートエントリが登録されないことがあるため、フォールバックパスにブートローダーを配置しておきます。

# chroot 環境内で実行
mkdir -p /boot/efi/EFI/BOOT
cp /boot/efi/EFI/ubuntu/grubx64.efi /boot/efi/EFI/BOOT/BOOTX64.EFI

chroot を抜けて、アンマウントします。

exit  # chroot を抜ける

sudo umount /mnt/newroot/sys/firmware/efi/efivars 2>/dev/null || true
sudo umount /mnt/newroot/sys
sudo umount /mnt/newroot/proc
sudo umount /mnt/newroot/dev/pts
sudo umount /mnt/newroot/dev
sudo umount /mnt/newroot/boot/efi
sudo umount /mnt/newroot

ステップ 4: 新 AMI 作成 → VMDK エクスポート

4-1. 非暗号化ディスクから新 AMI を作成

まず、インスタンスを停止します。次に、新しい非暗号化ディスクを元のインスタンスのルートボリューム(/dev/sda1/dev/xvda)としてアタッチし直します。

# インスタンスを停止
aws ec2 stop-instances --instance-ids i-xxxxxxxxxxxxxxxxx

# 元の暗号化ボリュームをデタッチ
aws ec2 detach-volume --volume-id vol-OLD_ENCRYPTED

# 新しい非暗号化ボリュームをルートデバイスとしてアタッチ
aws ec2 attach-volume \
  --volume-id vol-NEW_UNENCRYPTED \
  --instance-id i-xxxxxxxxxxxxxxxxx \
  --device /dev/sda1

インスタンスを起動して正常に動作することを確認してから、AMI を作成します。

# 起動確認
aws ec2 start-instances --instance-ids i-xxxxxxxxxxxxxxxxx

# 問題なければ再停止して AMI 作成
aws ec2 stop-instances --instance-ids i-xxxxxxxxxxxxxxxxx
aws ec2 create-image \
  --instance-id i-xxxxxxxxxxxxxxxxx \
  --name "ubuntu-unencrypted-for-export" \
  --no-reboot

4-2. VMDK エクスポート

新しい非暗号化 AMI をエクスポートします。

aws ec2 export-image \
  --image-id ami-NEW_UNENCRYPTED \
  --disk-image-format VMDK \
  --s3-export-location S3Bucket=<your-bucket>,S3Prefix=exports/

エクスポートの進捗は以下で確認できます。

aws ec2 describe-export-image-tasks \
  --export-image-task-ids export-ami-xxxxxxxxxxxxxxxxx

ステップ 5: ESXi への展開

5-1. VMDK のダウンロードと転送

S3 から VMDK ファイルをダウンロードし、ESXi のデータストアに転送します。

# S3 からダウンロード
aws s3 cp s3://<your-bucket>/exports/export-ami-xxxxx.vmdk ./

# ESXi に転送(scp の場合)
scp export-ami-xxxxx.vmdk root@<esxi-host>:/vmfs/volumes/datastore1/ubuntu-server/

ESXi に直接 wget する方法もあります(ESXi のシェルから S3 の署名付き URL にアクセス)。ファイルサイズが大きい場合はこちらが速い場合があります。

5-2. vmkfstools で変換

AWS からエクスポートされた VMDK はストリーム最適化形式(monolithicSparse)で、ESXi ではそのまま使えません。ESXi のシェルで変換します。

# ESXi にSSH接続
ssh root@<esxi-host>

# データストアに移動
cd /vmfs/volumes/datastore1/ubuntu-server/

# vmkfstools で thin provisioned 形式に変換
vmkfstools -i export-ami-xxxxx.vmdk ubuntu-server.vmdk -d thin

変換後、元のエクスポートファイルは削除して構いません。

5-3. VMX ファイルの作成

ESXi に VM を登録するための .vmx ファイルを作成します。

.encoding = "UTF-8"
config.version = "8"
virtualHW.version = "19"
displayName = "ubuntu-server"
guestOS = "ubuntu-64"
memsize = "2048"
numvcpus = "2"
firmware = "efi"

scsi0.present = "TRUE"
scsi0.virtualDev = "pvscsi"

scsi0:0.present = "TRUE"
scsi0:0.fileName = "ubuntu-server.vmdk"

ethernet0.present = "TRUE"
ethernet0.virtualDev = "vmxnet3"
ethernet0.networkName = "VM Network"
ethernet0.addressType = "generated"

ide1:0.present = "TRUE"
ide1:0.deviceType = "cdrom-raw"
ide1:0.startConnected = "FALSE"

重要な設定項目:

項目 理由
firmware efi 元が UEFI ブートのため。bios にすると起動しない
scsi0.virtualDev pvscsi パフォーマンスが良い。lsilogic でも動く
ethernet0.virtualDev vmxnet3 準仮想化 NIC。e1000 でも動くが性能は劣る

5-4. VM の登録と起動

ESXi の Web UI(Host Client)から VM を登録します。

  1. 「仮想マシンの作成/登録」→「既存の仮想マシンの登録」
  2. データストアから .vmx ファイルを選択
  3. 登録完了後、VM を起動

または CLI から登録する場合:

vim-cmd solo/registervm /vmfs/volumes/datastore1/ubuntu-server/ubuntu-server.vmx

ステップ 6: 初回ブート調整

VM が起動したら、AWS 環境固有の設定を削除・修正します。

6-1. cloud-init の無効化

AWS の Ubuntu AMI には cloud-init が入っています。ローカル環境ではメタデータサーバーにアクセスできないため、起動時に長時間ハングします。

GRUB のブートメニューが表示されたら、e キーで編集モードに入り、linux 行の末尾に以下を追加します。

cloud-init=disabled

起動後、cloud-init を完全に無効化・削除します。

# cloud-init を停止
sudo systemctl stop cloud-init
sudo systemctl disable cloud-init
sudo systemctl disable cloud-init-local
sudo systemctl disable cloud-config
sudo systemctl disable cloud-final

# 設定ファイルで無効化
sudo touch /etc/cloud/cloud-init.disabled

# 必要なら完全に削除
sudo apt purge cloud-init -y
sudo rm -rf /etc/cloud/ /var/lib/cloud/

6-2. fstab の整理

AWS 環境で使っていたマウント(EFS、インスタンスストア等)が fstab に残っている場合は、コメントアウトまたは削除します。

sudo nano /etc/fstab
# AWS 固有のマウントポイントを削除またはコメントアウト

6-3. NIC 名の修正

AWS 環境では NIC が ens5ens6 だったのが、ESXi では ens192ens160 に変わることがあります。ネットワーク設定を更新します。

# 現在の NIC 名を確認
ip link show

# Netplan の場合(Ubuntu 22.04)
sudo nano /etc/netplan/50-cloud-init.yaml

NIC 名を実際のデバイス名に書き換え、適用します。

sudo netplan apply

6-4. SSH ホスト鍵の再生成(任意)

AWS の cloud-init が生成した SSH ホスト鍵をそのまま使うのは気持ち悪いので、再生成しておきます。

sudo rm /etc/ssh/ssh_host_*
sudo dpkg-reconfigure openssh-server
sudo systemctl restart sshd

まとめ

全体の流れを整理すると、こうなります。

Lightsail スナップショット
  → EC2 AMI(暗号化済み)
  → インスタンス起動 + 非暗号化 EBS 追加
  → rsync でファイルコピー + GRUB/fstab 修正
  → 新 AMI 作成(非暗号化)
  → VMDK エクスポート(S3 経由)
  → ESXi に転送・vmkfstools で変換
  → VMX 作成・VM 登録・起動
  → cloud-init 無効化・NIC 修正

一番の壁は暗号化の解除でした。AWS は暗号化 EBS を非暗号化に変換する手段を提供していないため、 や dd で 非暗号化ディスクにデータをコピーするという回り道が必要です。

もうひとつ手間だったのが GRUB と EFI まわり です。パーティションの作成、UUID の書き換え、GRUB の再インストール、EFI フォールバックの配置と、Linux のブートプロセスを理解していないと詰まるポイントが多いです。

逆に、ESXi への展開自体は素直でした。vmkfstools で変換して VMX を書くだけです。

この手順は Lightsail に限らず、暗号化された EBS を持つ任意の EC2 AMI を ESXi に持ち出したい場合 に応用できます。同じ壁にぶつかった方の参考になれば幸いです。

Discussion