VPSの乗り換えはどこまで簡単?ロックイン監査
VPSの移行を妨げるのはOSより周辺層です。imageやsnapshotのexport、IPv6、DNS、前払い料金を監査し、移行作業を一晩に抑える方法を解説します。
VPS プロバイダー間でどの程度移行できますか?
VPS のロックインは現実にあります。ただし、多くの人が確認しない場所で発生します。KVM(kernel-based virtual machine)を実行する 2 つのプロバイダーでは、基盤の Ubuntu と systemd は同じです。そのため、OS が移行を妨げるわけではありません。移行を妨げるのは、サーバー周辺の層です。エクスポートできないイメージ、持ち出せない IP アドレス、DNS(domain name system)レコードも管理するコントロールパネル、返金されない前払い残高などです。
プロバイダーは、誰がサーバーを管理するかを決めます。しかし、移行できるかどうかを決めるわけではありません。この 2 つの事実の隔たりは、必要な作業時間として現れます。そして、その時間は必要になる前に短縮できます。
以下は監査手順です。時間に余裕があるときに、現在利用しているプロバイダーに対して実行してください。各手順は 1 つの質問で構成され、対応するコマンドまたは管理パネルでの確認方法と、後で問題になった場合の影響を示します。
実際の VPS ロックインとは
ロックインは契約書の条項ではありません。移行にかかる総コストです。誰も記録していない構成を再構築するための時間、データを外部へコピーするための帯域幅、リゾルバーが旧アドレスへ訪問者を送り続ける間のダウンタイム、そして使わない月の分まで支払った料金が含まれます。
この基準で見ると、VPS はレンタルできるサービスの中でも、ロックインが特に少ない部類です。汎用カーネル上で root を使用できます。マネージドデータベースや serverless プラットフォームでは、一晩では再実装できない API に依存します。一方、VPS がオペレーティングシステム層で依存させるものは、ほとんどありません。だからこそ、残るわずかな依存要素を把握しておく価値があります。それぞれ事前に対処すれば低コストですが、障害発生時に初めて気付くと高くつきます。
仮想化方式の監査 1: 現在の仮想化方式を確認する
systemd-detect-virt
lscpu | grep -i "hypervisor vendor"
uname -m
ls /sys/firmware/efi >/dev/null 2>&1 && echo UEFI || echo BIOSsystemd-detect-virtは 1 つの単語を出力します。kvmまたはxenの場合は完全仮想化です。独自の kernel を起動し、disk はホストが block device として扱う image file です。lxcの場合はホストの kernel を共有する container です。そのため、独自の kernel module をロードできず、nested virtualisation も利用できません。どちらの試行も Operation not supported で失敗します。これは command の問題ではなく、計画の問題です。VPS における KVM、Xen、LXC の違いでは、各モデルでできることとできないことを説明しています。
最後の 2 行は、disk をホスト間で移動するときに重要です。BIOS boot 用にインストールされた image は disk の boot sector に bootloader を保持します。一方、UEFI-only のホストは .efi loader を格納した EFI system partition を探しますが、見つからないため、コンソールで No bootable device の状態で停止します。より大きな制約となるのは architecture です。arm64 の root filesystem は x86_64 ホストでは起動できません。内部のすべての binary が異なる machine code だからです。その移行を検討している場合は、ARM と x86 の VPS プランで実際に異なる点で、価格以外の違いを確認できます。
監査 2: イメージを取り込めますか。また、持ち出せますか?
プロバイダーは、次のいずれかの位置に分類できます。パネルで該当するものを確認し、記録してください。
- プロバイダーが用意したイメージだけを選択できる。
- ISO を接続またはアップロードし、コンソールから自分でインストールする。
- アップロードしたディスクイメージ、または自分でホストした URL からディスクイメージをインポートする。
- ディスクイメージをエクスポートできる。4 つのうち、ディスクを持ち出せるかどうかを決めるのはこれだけです。
最初の 3 つは、どのように環境へ入るかを示します。環境から出る方法を示すのは 4 つ目だけです。しかし、多くのパネルにはこの機能がありません。インポートは顧客を受け入れ、エクスポートは顧客が出られるようにするため、この非対称性は一般的です。パネルに記載がない場合は、サポートへ直接問い合わせてください。問い合わせた日付と回答を記録します。
エクスポートに対応している場合は、移行先が受け入れられる形式に変換します。
qemu-img info disk.qcow2
qemu-img convert -p -O raw disk.qcow2 disk.rawRaw は最も広く受け入れられる形式ですが、移動には最も不便です。ファイルサイズがディスク全体の容量になるためです。使用量が 6 GB の 80 GB ボリュームでも、Raw ファイルは 80 GB になります。逆方向に qcow2 へ変換すると、qemu-img がゼロブロックを書き込まないため、使用量に近いサイズまで縮小できます。それでも、ディスク全体の転送は時間のかかる方法と考えてください。構成から再構築する方が、80 GB をインターネット経由でコピーするより通常は高速です。また、次回も再構築できるサーバーとして残せます。
監査 3: スナップショットをプロバイダーの外へ持ち出せるか
スナップショットのページを開き、スナップショットの横に表示される操作を確認します。操作が Restore だけなら、そのスナップショットはロールバック機能です。プロバイダーのストレージ上に保存され、アカウントを削除すると一緒に削除されます。また、自分のツールで読み取ることもできません。バックアップにはないスナップショットの機能で、この違いを詳しく説明しています。
ロックインとは無関係の制限もあります。稼働中のサーバーのスナップショットは、アプリケーション整合性ではなくクラッシュ整合性しかありません。書き込みの途中でディスクが取得されるため、復元時に PostgreSQL や MySQL がジャーナルを再生し、最後のトランザクションが失われる可能性があります。データベースはそれぞれのツールでダンプし、そのダンプをファイルレベルのバックアップで収集します。
ポータブルなバックアップとは、自分で保持するバックアップです。restic は、選択したストレージに暗号化済みの重複排除リポジトリを書き込みます。
sudo apt update && sudo apt install -y restic
sudo install -d -m 700 /etc/restic
sudo sh -c 'openssl rand -base64 32 > /etc/restic/password'
sudo chmod 600 /etc/restic/password
export RESTIC_REPOSITORY=sftp:backup@backup.example.com:/srv/restic
export RESTIC_PASSWORD_FILE=/etc/restic/password
sudo -E restic init
sudo -E restic backup /etc /srv /home
sudo -E restic snapshotsパスフレーズはサーバー以外の場所にも保管します。リポジトリのパスワードを失うと読み取れなくなり、サポートチケットでも復旧できないためです。次に、バックアップを実際に検証します。誰も復元したことのないバックアップは、推測にすぎません。
sudo -E restic restore latest --target /tmp/restore-check
sudo -E restic checkrestic snapshots には直前に実行したバックアップが表示され、/tmp/restore-check には実際に開けるファイルが保存されているはずです。月に 1 回復元を実行し、自分の目でファイルを 1 つ読み取ります。
監査 4: 持ち出せないアドレス
IP アドレスはプロバイダー間で移動できません。これは、この一覧で唯一の本当のロックイン要因です。対策は、これに対抗することではありません。すべてのアドレスの前に名前を置き、その名前をサーバーを購入していない会社で管理します。
ip -6 addr show scope global
ip -6 route show default
ping -6 -c 3 example.com
dig -x 203.0.113.10 +shortIPv6 では、移行時に必要な再作業の量を決める質問が2つあります。1つ目は、単一のアドレスが割り当てられるのか、ルーティングされた /64 が割り当てられるのかです。Web サーバーには1つのアドレスで十分ですが、すべてのコンテナに固有のアドレスを割り当てるには不十分です。2つ目は、そのアドレスが実際にルーティングされるかです。ip -6 addr にアドレスが表示され、ip -6 route show default の出力が空の場合、イメージはアドレスだけを設定し、ゲートウェイを設定していません。そのため、ローカルセグメント外からの応答はなく、IPv4 が通常どおり動作していても ping -6 はタイムアウトします。
dig -x は PTR レコードを確認します。PTR レコードは逆引き DNS であり、アドレスから名前へ戻すための設定です。出力が空の場合、PTR レコードはありません。メールサーバーでは、これは重大な障害になります。多くの受信側は、逆引き名が送信ホストと一致しないアドレスからのメールを拒否または遅延させるためです。パネルで PTR を自分で設定できるのか、それともサポートチケットが必要なのかを確認してください。この1つの項目によって、移行が2時間で終わるか、2日かかるかが決まります。セルフホスト型メールに今も手間をかける価値があるかでは、この一覧の残りを説明しています。
IP アドレスに紐付けてライセンスされたソフトウェアも、同じ理由で移行が難しくなります。cPanel のライセンスはサーバーのメイン IP に対して発行されるため、移行にはデータのコピーだけでなく、ライセンスの移転も必要です。知っておくべきコントロールパネルの代替製品は、1つにコミットする前のほうが比較しやすくなります。
監査 5: パネル機能のどれだけが API に対応しているか
パネルを確認し、各操作を API でも実行できるか確認します。対象には、作成、再構築、サイズ変更、スナップショット、ファイアウォールルール、reverse DNS、DNS レコード、2 つ目のログインの追加が含まれます。パネルでしか実行できない操作は、復旧計画の中で、担当者がボタンをクリックする作業になります。しかも、クリックが最も難しい時間帯に実行することになります。
アカウント自体も、書面上でテストしておく価値のある単一障害点です。支払いに失敗したり、ログインが不審と判定されたりしてアカウントが停止されると、サーバーが稼働していても管理できなくなる可能性があります。認証情報と最近取得したバックアップを、そのログインに依存しない場所にも保管します。また、2 要素認証を有効にして、停止の原因を自分で作る可能性を下げます。
DNS ホスティングは、個別に確認します。サーバーと同じパネル内にゾーンがある場合、そのプロバイダーから離れるときは、マシンの移行と同じ週に DNS も移行する必要があります。これは、リスクのある変更を 2 つ同時に行うことを意味します。ゾーンはレジストラまたは専用の DNS プロバイダーでホストし、レコードを git 内のテキストファイルで管理します。そうすれば、プロバイダーの移行は A レコードと AAAA レコードを数件編集するだけで済み、数秒で元に戻せます。
監査 6: 契約期間、残高、更新日
契約の詳細を確認すると、技術的には移行しやすいサーバーでも、解約しにくく高額なものになります。自分の請求書を確認し、次の4点を書き留めてください。最低契約期間、解約通知期間、未使用の前払い残高が返金可能かどうか、外部転送の許容量です。
最後の項目は、意外に思う人が多いかもしれません。300 GB のデータを外部へコピーすると、300 GB の送信トラフィックが発生します。従量課金制のプランでは、すでに2社へ料金を支払っている同じ月に、移行費用も発生します。移行を計画するときではなく、rsync の実行中になる前に許容量を確認してください。VPS の実際の月額費用と安価な VPS プランの読み方では、契約後になって初めて分かるプランの要素も説明しています。
日本のプロバイダーから円で購入する場合は、最初の2項目を特に注意して確認してください。月単位の最低契約期間は一般的です。前払い残高も一般的です。さらに、1社のプロバイダーを何年も使い続けることも珍しくありません。そのため、アカウント開設後に契約条件を読み直していないことがよくあります。コンソールの操作方法もプロバイダーごとに異なります。同じ操作でもメニューの場所が異なるため、移行担当者は時間が進む中で新しい管理画面を覚えることになります。これらはすべて、更新日前の余裕がある週に確認するのが適しています。アカウントを閉鎖すると snapshots とバックアップは削除されると想定し、保持したいものは最終日までにダウンロードしてください。
移植性を確保する方法: 2 つのファイルと 1 つのバックアップ
監査により、現在の状態が分かります。ここで説明する方法により、移行先での回答を探す必要がなくなります。
cloud-init ファイルで設定する。 cloud-init は、初回起動時にクラウドインスタンスを設定するツールです。ほぼすべてのプロバイダーイメージに含まれており、ほぼすべての管理パネルに貼り付け用の user data フィールドがあります。
#cloud-config
hostname: web01
users:
- name: deploy
groups: [sudo]
shell: /bin/bash
sudo: "ALL=(ALL) NOPASSWD:ALL"
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA deploy@workstation
package_update: true
packages:
- docker.io
- docker-compose-v2
- restic
runcmd:
- [systemctl, enable, --now, docker]管理パネルに入力する前にファイルを検証し、実行中のサーバーで結果を確認します。
cloud-init schema --config-file user-data.yaml
cloud-init status --long
sudo cloud-init schema --systemcloud-init status --long は status: done を報告するはずです。error が報告された場合は、末尾から /var/log/cloud-init.log を確認します。最も一般的な失敗は、先頭行に #cloud-config がないことです。これがないと cloud-init はテキストを設定として認識せず、ファイル全体をエラーなしで無視します。その結果、管理パネルにエラーが表示されないまま、ユーザーが作成されずログインに失敗することがあります。新しい VPS 用に cloud-init の user data を記述するでは、設定すべき項目を説明しています。
ここには注意点が 1 つあります。User data はインスタンス ID をキーとして、インスタンスごとに 1 回だけ実行されます。スナップショットを復元してもインスタンス ID は変わらないため、ファイルの内容は再実行されません。このファイルは新しいサーバーを構築するためのものです。既存のサーバーを修復するものではありません。
Compose ファイルでサービスを定義する。 すべてのイメージにバージョンタグを固定し、docker-compose.yml を git で管理します。さらに、ファイルの内容が実際の実行状態を記述していることを確認します。
docker compose config
docker volume lsdocker compose config は、変数を解決した統合済みファイルを出力します。この出力が実行中のスタックと一致しない場合、このサーバーでは手作業で変更された部分があります。その部分は次のサーバーに確実に引き継がれません。新しいホストの再起動後にスタックが復旧するよう、すべてのサービスで restart: unless-stopped を設定します。systemd 側の設定については、Compose スタックを起動時に開始するで説明しています。
名前付きボリュームは、プロジェクトディレクトリの外部にあるため忘れられがちです。
docker run --rm -v app_data:/data -v "$PWD:/backup" alpine tar czf /backup/app_data.tar.gz -C /data .新しいサーバーでは、同じイメージを tar xzf で復元し、先に docker volume create app_data で作成したボリュームに格納します。
サーバー外部のバックアップにデータを保存する。 これは Audit 3 で確認した restic リポジトリです。旧プロバイダーにも新プロバイダーにも属さないストレージに保存します。
リハーサルを行う。 2 つのファイルと最後のバックアップを使い、借りられる最も安価なインスタンスで一連の作業を 1 回実施し、所要時間を計測します。その時間が、時間単位で測定した実際のロックインです。移行作業自体は別の作業です。実行中のサーバーを新しい VPS に移行するでは、コピーと切り替えの手順を説明しています。
必要になる前に DNS TTL を短くする
すべての DNS レコードには TTL(time to live)が設定されています。これは、リゾルバーがレコードをキャッシュしてよい秒数です。86400 のレコードは 1 日間キャッシュされるため、アドレスを変更した後も、訪問者によっては 1 日間、古いサーバーにアクセスし続けます。TTL を短くする場合も即時には反映されません。キャッシュには、古い長い TTL の値が期限切れまで保持されるためです。
先に TTL を短くし、切り替えまで元の TTL の期間いっぱい待ちます。
dig +noall +answer example.com A
dig +noall +answer @ns1.example.com example.com A最初のクエリは使用中のリゾルバーに送信されます。表示される TTL は、キャッシュされたコピーの経過時間に応じて減少します。2 番目のクエリは権威 DNS サーバーに送信されます。権威 DNS サーバーは、設定した値を常に返します。移行中は 300 に設定し、1 週間後に元の値へ戻します。
切り替え後も、少なくとも元の TTL の期間は旧サーバーを稼働させてください。その間もトラフィックが旧サーバーに到達するためです。アプリケーションが書き込みを受け付ける場合は、その期間中、旧コピーを読み取り専用にします。2 つの稼働中のコピーが同時に書き込みを受け付けると、データが分岐します。その状態は、どのようにリストアしても修復できません。
クローン後に問題になるもの: ID と時刻
クローンまたは復元したサーバーには元のサーバーの ID が引き継がれます。起動時に警告は表示されません。
最初は /etc/machine-id です。systemd はここから、systemd-networkd が使用する DHCP クライアント ID など、ほかの識別子を導出します。そのため、2 台のクローンが同じリースを要求し、1 つのアドレスを交互に保持することがあります。クローンを運用に投入する前にリセットします。
sudo rm -f /etc/machine-id /var/lib/dbus/machine-id
sudo systemd-machine-id-setup
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
sudo rebootVPS のクローン作成後に machine-id を完全にリセットする方法では、監視エージェントが保持するファイルなど、ID を含むその他のファイルも扱います。
次は SSH ホスト鍵です。クローンは元のサーバーと同じホスト鍵で応答します。そのため、クライアントから 2 台のサーバーを区別できず、新しいアドレスで以前の名前に接続すると REMOTE HOST IDENTIFICATION HAS CHANGED が表示されます。
sudo rm -f /etc/ssh/ssh_host_*
sudo ssh-keygen -A
sudo systemctl restart ssh現在のセッションはその再起動後も維持されます。2 つ目のセッションを開き、1 つ目のセッションを閉じる前にログインできることを確認します。自分のマシンでは、ssh-keygen -R 203.0.113.10 で古いエントリを削除します。
3 番目は時刻です。復元したスナップショットは、スナップショット取得時点の時刻で起動するため、数週間遅れていることがあります。timedatectl を実行し、2 行を確認します。System clock synchronized: no と NTP service: active が同時に示されていれば、同期は開始していますが完了していません。これほど時刻が遅れていると、サーバーから見て証明書の開始日時がまだ未来になるため、最新の TLS (transport layer security) 証明書が certificate is not yet valid で拒否されます。同じ理由で、時刻ベースのワンタイムパスワードによるログインも失敗します。
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
timedatectl4 番目はインターフェース名です。Netplan の設定ではインターフェース名を指定しますが、プロバイダーによって名前が異なります。一方では ens3、別のプロバイダーでは enp1s0 です。ens3 を指定したファイルは新しいホスト上のどのデバイスにも一致しないため、インターフェースが起動せず、コンソールだけが使用可能になります。代わりにパターンで一致させます。
network:
version: 2
ethernets:
primary:
match:
name: "en*"
dhcp4: true
dhcp6: true古いサーバーで sudo netplan get を実行すると、実際に設定されている内容を確認できます。新しいサーバーでは sudo netplan try を実行します。接続が切断された場合、このコマンドは変更を自動的に元に戻します。
更新時ではなく、障害が発生していない時点で監査する
回答は cloud-init ファイルの横に、確認した日付とともに書き留めます。更新のたびに用語は変わり、管理パネルには機能が追加されます。昨年は存在しなかったエクスポートボタンが、今は追加されている可能性もあります。
監査にかかる時間は、内容を読む 1 時間です。手順の実施は半日です。その後は、プロバイダーの移行が一大プロジェクトではなく、一晩の作業で済みます。また、プロバイダーを置き換えられるかどうかについても、推測ではなく、測定した結果に基づいて判断できます。
FAQ
VPS lock-in は、すべてのプロバイダーが Linux を実行していても実在しますか?
はい。ただし、オペレーティングシステムの層ではありません。ある KVM ホスト上の Ubuntu は別の KVM ホスト上の Ubuntu と同じように動作するため、実行するソフトウェアは通常、そのまま移植できます。lock-in は周辺部分にあります。エクスポートできないスナップショット、移行できない IP アドレス、自分で編集できない reverse DNS、サーバーと同じパネルで管理される DNS zone、返金されない前払い残高などです。これらはすべて 1 時間あれば確認でき、必要になる前に対処できます。
VPS のスナップショットをエクスポートして、別のプロバイダーで起動できますか?
パネルにエクスポートまたはダウンロード操作がある場合に限ります。対応していないプロバイダーも多くあります。スナップショットの横にある操作が Restore だけなら、そのスナップショットは 1 つのプロバイダー内でしか使用できません。エクスポートできる場合でも、イメージは移行先の条件に適合する必要があります。同じ CPU アーキテクチャーであり、新しいホストがサポートする boot mode でなければなりません。restic などのツールで、自分が管理するストレージにファイル単位のバックアップを保存すれば、これらの条件に左右されず、どのホストにも復元できます。
DNS TTL はどのくらい前に短くすべきですか?
少なくとも、現在の TTL が 1 回完全に経過する前に短くします。リゾルバーは、以前の値が期限切れになるまでその値を保持します。そのため、86400 のレコードでは、変更から移行まで 1 日空ける必要があります。移行中は 300 に設定し、dig +noall +answer @ns1.example.com example.com A で authoritative server 上の値を確認します。レコードを切り替えた後も、さらに 1 TTL の間は旧サーバーが応答する状態を維持します。
サーバーを新しいプロバイダーにクローンすると、何が壊れますか?
4 つあります。いずれもエラーが表示されずに発生します。重複した /etc/machine-id が元のサーバーと衝突し、2 台のサーバーが 1 つの DHCP lease を共有する状態になることがあります。SSH host key も重複するため、クライアントは 2 台のマシンを区別できません。NTP が追いつくまで clock はスナップショット取得時点のままになり、新しい TLS 証明書がまだ有効ではないように見えます。また、network configuration が新しいホストに存在しない interface を指定していると、サーバーは network なしで起動し、接続できるのは console だけになります。
この監査は更新前に実行すべきですか、それとも移行中に実行すべきですか?
更新前です。移行中は新しいパネルを覚え、データコピーを監視し、DNS の反映を待つ必要があります。その時点で、契約期間があと 5 か月残っていることや、スナップショットをエクスポートできないことに気付くのは適切ではありません。更新日の数週間前に、落ち着いて 1 時間確認しておけば、更新するかどうかを判断する根拠が変わります。