暗号化された 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
つまり:
- 暗号化 AMI からインスタンスを起動する
- 非暗号化の空 EBS ボリュームを追加でアタッチする
- rsync でファイルシステムの中身を丸ごとコピーする
- 非暗号化ディスクから新しい 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 を登録します。
- 「仮想マシンの作成/登録」→「既存の仮想マシンの登録」
- データストアから
.vmxファイルを選択 - 登録完了後、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 が ens5 や ens6 だったのが、ESXi では ens192 や ens160 に変わることがあります。ネットワーク設定を更新します。
# 現在の 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