DigitalOcean から Hetzner に移行すること

2026/04/18 22:29

DigitalOcean から Hetzner に移行すること

RSS: https://news.ycombinator.com/rss

要約

日本語翻訳:

トルコ発のソフトウェア企業が、DigitalOcean から専用 Hetzner サーバーへのシームレスなゼロダウンタイム移行を成功させ、巨額の経費削減と大幅なハードウェアアップグレードを実現しました。特に印象的なのは、月次費用を 1,432 ドルからわずか 233 ドルへ削減しつつ、旧型の vCPU/SSD スペックを、NVMe ストレージを搭載した高性能 AMD EPYC プロセッサへとインフラストラクチャをアップグレードしたことです。この移行は、GitLab や Neo4j などのクリティカルなアプリケーションを多数利用者に提供するという複雑な生産環境において、大きな中断なしに実行されました。

本プロジェクトは、248 GB のデータをマルチスレッドバックアップと rsync を用いて高速に移動させる堅固な 6 段階移行戦略に基づいていました。主要な技術的なハイライトとしては、データベースシステムを MySQL 5.7 からバージョン 8.0 へ、オペレーティングシステムを CentOS 7 から AlmaLinux 9.7 へとアップグレードしたことです。チームは、

mysql.user
テーブルのスキーマ不一致の解消、再пликаケーション時の重複キーエラーを冪等な実行モードで対処し、SUPER プライバリジの取り消しによるセキュリティ脆弱性の是正など、複数の重要な技術的障壁を克服することに成功しました。DNS プロパゲーション期間がわずか 5 分であったにも関わらず、サービスは安定していました。同チームは、この費用対効果の高いアプローチを他者に複製できるよう、Python 製の移行スクリプトを GitHub でオープンソース化しています。

本文

デジタルオシアンからヘッツナー・デディケイテッドサーバーへの本番環境移行:248GB の MySQL データ(30 のデータベース)、34 の Nginx サイト、GitLab EE、Neo4j、および多数ユーザーにサービスを提供しているモバイルアプリのトラフィックを完全に中断することなく成功裏に実行しました。

移転した理由

トルコでソフトウェア企業を経営するのは、近年ますます高価になっています。暴騰するインフレ率と米国ドルに対するトルコリラの著しい価値低下により、ドル建てでのインフラコストが深刻な負担となりました。2 年前には妥当に見えた請求額も、為替相場が数倍に跳ね上がった今では全く異なる衝撃をもたらします。

私たちは毎月の DigitalOcean(ドロープル)利用料として、192GB の RAM、32vCPU、600GB SSD、および 2 つのブロックボリューム(それぞれ 1TB)、バックアップ機能付きで $1,432 を支払っていました。サーバー自体は問題なかったのですが、パフォーマンスに対する単価が意味をなさなくなってしまいました。

その時、ヘッツナー AX162-R というサーバーを発見しました。

特徴DigitalOceanHetzner AX162-R
CPU32 vCPUAMD EPYC 9454P (48 コア / 96 スレッド)
RAM192 GB256 GB DDR5
ストレージ600 GB SSD + 2x1 TB ボリューム1.92 TB NVMe Gen4 RAID1
月次コスト$1,432$233
節減額月間 $1,199

これは年間 $14,388 を節約できる計算です。かつ、すべての面で客観的に高性能なサーバーです。決断は容易でした。

私は約 8 年間 DigitalOcean の顧客でしたが、製品自体は大変良く、信頼性や開発者体験については不満はありませんでした。しかし、今これらの数字を見る限り、これまでの年間で失っていた資金に少し淋しさを感じざるを得ません。もし定常的なワークロードを処理し、DigitalOcean のエコシステム機能は能動的に利用していないのであれば、次の更新前にデディケイテッドサーバーの価格を確認することを強くお勧めします。

稼働していた環境

これは玩具のようなプロジェクトではありませんでした。スタックには以下が含まれていました:

  • MySQL データベース 30 つ(データ量 248GB)
  • 複数のドメインで運用されている Nginx 仮想的ホスト 34 カ所
  • GitLab EE(バックアップ容量 42GB)
  • Neo4J グラフデータベース(グラフ DB コンテンツ 30GB)
  • 多数の背景ワーカーを管理する Supervisor
  • Gearman ジョブキュー
  • 数十万のユーザーにサービスを提供している複数種類のライブモバイルアプリ

旧サーバー: CentOS 7 —— エンド オブ ライフ已过ですが、まだ運用環境で稼働中。
新サーバー: AlmaLinux 9.7 —— RHEL 9 と互換性があり、CentOS の自然な後継者です。この移行は、数年間セキュリティ更新を受けなかった OS からついに解放される機会でもありました。

戦略:ゼロ ダウンタイム

DNS を変更して全サービスを再起動し、ベストを祈るような素朴なアプローチは許されませんでした。代わりに、6 つのフェーズからなる適切な移行計画を策定しました:

フェーズ 1 —— 新しいサーバーへの全スタックインストール

Nginx(ソースコードからのコンパイルでフラグを同一にしたもの)、PHP(Remi リポジトリ経由で旧サーバーと同じ .ini 設定ファイルを使用)、MySQL 8.0、Neo4J グラフ DB、GitLab EE、Node.js、Supervisor、Gearman の全サービスが、DNS レコードに触れる前の段階ですべて旧サーバーの挙動と一致するように設定されました。

SSL 証明書は、旧サーバーから

/etc/letsencrypt/
ディレクトリ全体を
rsync
で転送する方式で処理しました。移行完了後、すべてのトラフィックが新しいサーバーを経由し始めたタイミングで、一度にすべての証明書の強制更新を行いました:

certbot renew --force-renewal

フェーズ 2 —— Web ファイルのクローン化(rsync)

/var/www/html
ディレクトリ全体(約 65GB、150 万個のファイル)を SSH を介した
rsync --checksum
フラグを用いて新しいサーバーにクローンしました。スイッチオーバー直前には、初期クローン後に更新されたファイルを捕捉する最終的なインクリメンタル同期を実行しました。

フェーズ 3 —— MySQL マスターからスレーブへのレプリケーション設定

データベースをオフラインにしてダンプ・レストアを行うのではなく、ライブ レプリケーションを設定しました。旧サーバーをマスター、新サーバーをリーダースレーブとしました。初期バッチ読み込みには

mydumper
を使用し、ダンプメタデータに記録された正確な binlog ポジションからレプリケーションを開始しました。これにより、スイッチオーバーの瞬間まで両方のデータベースがリアルタイム同期を維持できました。

フェーズ 4 —— DNS TTL の削減

DigitalOcean DNS API をスクリプト化して、すべての A レコードと AAAA レコードの TTL を 3600 秒から 300 秒に低下させました(MX または TXT レコードには触れず、メールレコードの TTL 変更は配信性に影響を与える可能性があるため)。1 時間経過して古い TTL がグローバルに破棄されるのを待ち、その時点で DNS クイックスウィッチオーバー(転換)を行い、所要時間は 5 分以内に収めました。

フェーズ 5 —— 旧サーバーの Nginx をリバースプロキシへの変換

Python スクリプトを作成し、34 の Nginx サイト設定のうちすべての

server {}
ブロックを解析し、オリジナルのバックアップを取りながら、新しいサーバーへのプロキシ構成に置換しました。これにより、DNS プロパゲーション期間中に古い IP にアクセスされたリクエストも静かに転送され、ユーザーにはどの障害も認識されませんでした。

フェーズ 6 —— DNS クイックスウィッチオーバーと旧サーバーの廃止

単一の Python スクリプトが DigitalOcean API にアクセスし、A レコードをすべて新しいサーバー IP に切り替える作業を行い、わずか数秒で完了しました。旧サーバーは冷 standby(待機)として 1 週間維持した後、シャットダウンされました。

重要な知見: サービスが使えなくなる時間帯は一切存在しませんでした。トラフィックは常に直接アクセスされるか、あるいはプロキシ経由で提供されていました。

MySQL データ移行

これはこの全操作の中で最も複雑な部分でした。

データのダンプ化

標準的な

mysqldump
の代わりに
mydumper
を使用し、驚くべき性能向上を得ました。新しいサーバーの 48 コア CPU を並列エクスポートおよびインポートに活用した結果、従来シングルスレッドの
mysqldump
で数日かかっていた作業が数時間で完了しました。大規模な MySQL データベースを移行する際に
mydumper/myloader
を使用しない場合は、困難なやり方を行っていることになります。

mydumper \
  --threads 32 \
  --compress \
  --trx-consistency-only \
  --skip-definer \
  --chunk-filesize 256 \
  -v 3 \
  --outputdir /root/mydumper_backup/

主なダンプのメタデータファイルには、スナップショット時点の binlog ポジションが記録されました:

  • ファイル: mysql-bin.000004
  • ポジション: 21834307

これがレプリケーションの開始ポイントとなります。

ダンプデータの転送(新サーバーへ)

ダンプ完了後、SSH を介した

rsync
でデータを新サーバーに転送しました。圧縮されたチャンクが 248GB に達していたため、他の転送方法よりもはるかに高速でした:

rsync -avz --progress /root/mydumper_backup/ root@NEW_SERVER:/root/mydumper_backup/

ここで

mydumper
--compress
フラグの効果が顕著に表れました。圧縮されたチャンクがネットワーク回路上で素早く転送されました。

データの読み込み

myloader \
  --threads 32 \
  --overwrite-tables \
  --ignore-errors 1062 \
  --skip-definer \
  -v 3 \
  --directory /root/mydumper_backup/

MySQL 5.7 から 8.0 への移行問題

CentOS 7 で固定されていたため、MySQL 5.7(数年間運用されてきた陳腐化バージョン)でも固定されていました。移行前には

mysqlcheck --check-upgrade
を実行し、データが MySQL 8.0 と互換性があることを確認しました。結果はクリアだったので、新しいサーバーに最新の MySQL 8.0 コミュニティエディションをインストールしました。すべてのプロジェクトで即座にパフォーマンス改善が見られました——MySQL 8.0 の改良されたオプタイマイザーと InnoDB 拡張機能によりクエリ実行時間が大幅に減少しました。

ただし、バージョンアップは一つの微妙な問題を招きました。 インポート後、

mysql.user
テーブルの列構造が誤っており、期待される 51 列に対して 45 列となっていました。その結果
mysql.infoschema
が欠落し、ユーザー認証が失敗しました。

修正方法:

systemctl stop mysqld
mysqld --upgrade=FORCE --user=mysql &

しかし、最初の実行では以下のエラーが発生しました:

ERROR: 'sys.innodb_buffer_stats_by_schema' is not VIEW
sys スキーマがビューとしてではなく普通テーブルとしてインポートされていました。解決策:再度アップグレードを実行。成功。

MySQL レプリケーションの設定

両方のダンプをインポートした後、新しいサーバーを旧サーバーのレプリカとして設定しました:

CHANGE MASTER TO
  MASTER_HOST='OLD_SERVER_IP',
  MASTER_USER='replicator',
  MASTER_PASSWORD='...',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='mysql-bin.000004',
  MASTER_LOG_POS=21834307;

START SLAVE;

ほぼ即座にレプリケーションがエラー 1062(重複キー)で停止しました。これはダンプを 2 パスで行ったため、その間のギャップで特定テーブルに行が書き込まれ、インポートされたダンプと binlog の再生の両方で同じ行を挿入しようとしたことが原因です。

修正方法:

SET GLOBAL slave_exec_mode = 'IDEMPOTENT';
START SLAVE;

IDEMPOTENT モードでは、重複キーエラーや行欠落エラーを静かにスキップします。すべての重要データベースが 1 つのエラーもなく同期されました。数分後には

Seconds_Behind_Master
が 0 に落ちました。

クイックスウィッチオーバー前のテスト

DNS レコードを触る前に、新サーバー上の全サービスが正しく動作しているかを確認する必要がありました。トリック:ローカルマシンの

/etc/hosts
ファイルを一時的に編集し、ドメイン名を新サーバーの IP に指し示すようにしました。

# /etc/hosts(ローカルマシン)
NEW_SERVER_IP  yourdomain1.com
NEW_SERVER_IP  yourdomain2.com
# ... それぞれすべてのドメインに対して同様

これにより、ブラウザと Postman は新しいサーバーにアクセスしましたが、世界の他の場所は依然として古いサーバーへ行きました。API エンドポイントをテストし、管理パネルを確認し、各サービスが正しく応答しているか検証しました。この確認後にのみクイックスウィッチオーバーに進みました。

隠された SUPER権限の問題

マスターとスレーブ間のレプリケーションが完全に同期した後、新しいサーバーでは本来あるべきではないときに INSERT ステートメントが成功していたことに気づきました。

read_only = 1
が設定されていましたが、書き込みが行われていました。

理由:すべての PHP アプリケーションユーザーに SUPER 権限が付与されていました。MySQL において、SUPER は

read_only
を回避します。

SHOW GRANTS FOR 'some_db_user'@'localhost';
-- 結果: GRANT SELECT, INSERT, UPDATE, DELETE, ..., SUPER, ... ON *.*

24 のアプリケーションユーザーからすべて撤回しました:

REVOKE SUPER ON *.* FROM 'some_db_user'@'localhost';
-- すべてのユーザーに対して繰り返し実行
FLUSH PRIVILEGES;

その後、

read_only = 1
がアプリケーションユーザーからのすべての書き込みを正しくブロックしながら、レプリケーションの継続を許容しました。

DNS の準備

すべてのドメインは DigitalOcean DNS を通じて管理されており(ネームサーバーは GoDaddy から指し示されていました)、DigitalOcean API に対して TTL 削減スクリプトを作成しました。MX または TXT レコードには触れず、メールレコードの TTL 変更は Google Workspace との配信性に影響を与える可能性があるためです。

# A と AAAA レコードのみを対象
if record["type"] in ("A", "AAAA"):
    update_record_ttl(domain, record["id"], 300)

古い TTL が破棄されるのを待ち、1 時間経過後、準備完了でした。

旧サーバー Nginx をリバースプロキシへの変換

34 の設定ファイルを manualmente 編集するのではなく、すべての設定ファイル内の

server {}
ブロックを解析し、主要なコンテンツブロックを特定してプロキシ構成に置換し、オリジナルを
.backup
ファイルとしてバックアップする Python スクリプトを書きました。

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    location / {
        proxy_pass https://NEW_SERVER_IP;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_ssl_verify off;
        proxy_read_timeout 150;
    }
}

重要点:

proxy_ssl_verify off
— 新しいサーバーの SSL 証明書はドメインに対して有効であり、IP アドレスに対しては有効ではありません。両方を経営しているため、ここでは検証を無効化しても問題ありません。

クイックスウィッチオーバー

レプリケーションが

Seconds_Behind_Master: 0
で、リバースプロキシも準備できた時点で、以下の順序でクイックスウィッチオーバーを実行しました:

  1. 新サーバー:
    STOP SLAVE;
  2. 新サーバー:
    SET GLOBAL read_only = 0;
  3. 新サーバー:
    RESET SLAVE ALL;
  4. 新サーバー:
    supervisorctl start all
  5. 旧サーバー:
    nginx -t && systemctl reload nginx
    (プロキシが稼働)
  6. 旧サーバー:
    supervisorctl stop all
  7. Mac:
    python3 do_cutover.py
    (DNS: すべての A レコードを新サーバー IP に切り替え)
  8. 待機:伝播完了まで約 5 分
  9. 旧サーバー:全 crontab エントリーをコメントアウト

DNS クイックスウィッチオーバースクリプトは DigitalOcean API にアクセスし、すべての A レコードを新サーバー IP に変更しました——所要時間は約 10 秒です。

クイックスウィッチオーバー後の最後の作業

移行後、多数の GitLab プロジェクトウェブフックが依然として旧サーバー IP を指していたことに気づきました。GitLab API を通じてすべてのプロジェクトをスキャンし、バッチで更新するスクリプトを作成しました。

最終的な数値

$1,432/月から $233/月へと減少し、年間 $14,388 を節約しました。かつ、より高性能なマシンを手に入れました:

  • CPU: 32vCPU から 96 ロジカル CPU(AMD EPYC 9454P、48 コア x 2 スレッド)へ
  • RAM: 192GB から 256GB DDR5 へ
  • ストレージ:混合された約 2.6TB から 2TB NVMe RAID1 へ
  • ダウンタイム:0 分

全体的な移行は約 24 時間で行われました。ユーザーへの影響はありませんでした。

主な教訓

  • MySQL レプリケーションはゼロダウンタイム移行のための最良の友です。早期に設定し、追いつかせることで、確信を持ってクイックスウィッチオーバーを実行できます。
  • 移行前に MySQL ユーザー権限を確認してください。SUPER 権限は
    read_only
    を回避するため、アプリユーザーが持っていればスレーブ環境は実際にはリードオンリーではありません。
  • 全てをスクリプト化してください。DNS 更新、Nginx 構成書き換え、ウェブフック更新などを 34 カ所以上のサイトで行うと時間がかかるうえにエラーを起こす可能性があります。
  • mydumper
    +
    myloader
    は大規模データセットに対して大幅に
    mysqldump
    よりも優れています。32 スレッドによる並列ダンプ/レストアによって、元数日かかっていた作業を数時間に短縮できました。
  • クラウドプロバイダーは定常ワークロードには高価です。オートスケーリングまたは一時的インフラストラクチャを使用していない場合、デディケイテッドサーバーはわずかなコストでより高いパフォーマンスを提供することが多いです。

全てのスクリプト GitHub に公開

この移行で使用したすべての Python スクリプトはオープンソース化されており、GitHub で入手可能です:

  • do_list_domains_ttl.py
    — DigitalOcean のドメインおよび A レコード、IP、TTL をリスト
  • do_ttl_update.py
    — A/AAAA レコードの TTL をバッチで 300 秒に削減
  • do_to_hetzner_bulk_dns_records_import.py
    — DNS ゾーンを DigitalOcean から Hetzner DNS へ移行
  • do_cutover_to_new_ip.py
    — すべての A レコードを旧サーバー IP から新サーバー IP に切り替え
  • nginx_reverse_proxy_update.py
    — すべての Nginx サイト設定をリバースプロキシ構成に変換
  • mysql_compare.py
    — 2 つの MySQL サーバー間でのテーブルごとの行数を比較
  • final_gitlab_webhook_update.py
    — すべての GitLab プロジェクトウェブフックを新サーバー IP に更新
  • mydumper
    — mydumper ライブラリ

すべてのスクリプトは安全に変更内容を適用前にプレビューできる

DRY_RUN = True
モードをサポートしています。

同じ日のほかのニュース

一覧に戻る →

2026/04/19 5:54

『好みの色を選べる:NIST の科学家らが、任意の波長のレーザーを開発』

## Japanese Translation: NIST の科学者と協力者が、Scott Papp という NIST の物理学者をリーダーとして発表された「Monolithic 3D integration of tantalum pentoxide nonlinear photonics」という論文に詳述されているように、特殊な材料の複雑なパターンをシリコンウエハーに堆積させることで、統合光子デバイスのチップ作成における画期的手法を開発しました。この革新は、サイズ、コスト、電力に関する重要な歴史的制約を解決し、量子コンピューティングなどの高度な技術用のコンパクトで高品質なレーザーの実現を可能にします。酸化シリコン、リチウムニオブате、タンタル五酸化物(単一のレーザー色を多様な波長に変換しつつ過度の発熱を抑える材料)を含むマルチレイヤーアプローチを用いることで、チームはビールコスター程度のサイズのパターンに、約 10,000 の光子回路を備えた指先ほどの大きさのチップを約 50 個集積することに成功しました。以前是高品質なレーザーは特定の波長(例:980 nm の赤外線)のみに存在し、量子技術の利用が専門的な研究室に限定されていましたが、この画期的進展により、携帯型光原子時計や地震予測システムといった現場での応用が可能になります。光原子時計や量子コンピュータなどの量子技術には、ルビジウム(780 nm の赤)やストロンチウム(461 nm の青)など、異なる原子に合わせた特定の色のレーザーが多く必要とされますが、この新技術はそれを効果的に解決します。この技術は、効率的な光処理を必要とする産業において量子デバイスへのアクセスを民主化するだけでなく、研究機関と Octave Photonics などのスタートアップ間の協力を促進します。*Nature* に掲載されたこれらの発見は、光子機能と電気システムを統合する道を開き、人工知能から暗物質調査に至るまでの分野を変革する可能性があります。これにより、複雑な科学ツールが従来の実験室の外でも手頃な価格で利用できるようになります。

2026/04/19 1:26

ボーイング社の B-52 ストラトフォートレス爆撃機に搭載された、スタートラッカー内の電気式傾斜計。

## Japanese 翻訳: アストロコンパスは、1960 年代の B-52 爆撃機向けに開発され、乗組員が手動で行っていた複雑な三角法の計算を自動化し、天体航法を画期的に変化させました。ジャミングに脆弱な現代デジタルシステムと異なり、この電気機械装置は、外部デジタル信号を使用せずに、シンクロン(変送機)および光増倍管を用いて恒星を追跡する信頼性の高い抗ジャミング方式を提供しました。恒星位置の物理的な追跡と天球のアナログモデルを組み合わせることで、システムはパイロットにリアルタイムでの航法更新を通じて正確な位置を決定することを可能にしました。 公式空軍年誌からのデータに基づいて動作し、この装置は時間や恒星の赤緯などの入力をノブで調整するマスターコントロールパネルを搭載していました。これらの設定は、安定したジャイロプラットフォームとガラスドーム型望遠鏡を含む組立体内の 19 のコンポーネントを駆動しました。アストロコンパスは「位置線」技術を使用し、測定された恒星の高度を計算された期待値と比較することで航空機の軌跡を特定しました。この自動化により、困難な手動手順はスムーズな電気機械プロセスへと変換され、爆撃機艦隊が重要な航法任務において、作戦能力とミッション安全性を大幅に向上させました。

2026/04/19 4:19

Claude のデザインに関する考察と感情

## 日本語翻訳: 要約:中心的な論点是、Figma の専用でロックされたファイル形式がネイティブのスキーマを持たず、深いエイリアシングおよび未文書化されたプリミティブに依存を迫られること(例:946 色の変数を含むネストされたグループのあるファイル)であり、これがコードトレーニング済みの AI モデルが設計論理を正確に解釈することを妨げる。LLM はこれらの特定の不透明な Figma 構造ではなくコードに対してトレーニングされているため、「Figma Make」のような現在のツールは、設計ファイルが依然として規範的であると示唆することでユーザーを誤導し、実質的にワークフローを新しいエージェント時代と不相容の専用エコシステムにロックしている。その対応として、Claude Design とような新たなツールは、「HTML と JS をすべて徹底する」というアプローチを取り、コードと直接統合してレポジトリから AI エージェントへ供給される統一されたフィードバックループを創出する。著者は業界における分岐の予測を行う:一方は誠実なコード連結による生産ツールへの道筋、他方は Photoshop に似た制約のない探求環境への道筋となる。クリーンなコードからのこの転換を批判しつつも、著者は Sketch などの競合業者に対してネイティブ機能に安住するのではなく、粒子エフェクトやメッシュ変換などの特定機能を備えた革新を促し、Figma の形式が AI エージェントに必要なトレーニングデータへの含まれにくさを指摘している。 ## テキストを翻訳 (必要に応じて;そうでない場合は元のものを繰り返す): ## Summary: The core argument is that Figma's proprietary, locked-down file format lacks a native schema, forcing reliance on deep aliasing and undocumented primitives (exemplified by files containing 946 color variables within nested groups) that prevent code-trained AI models from accurately interpreting design logic. Because LLMs were trained on code rather than these specific, opaque Figma structures, current tools like "Figma Make" are misleading users by suggesting the design file remains canonical, effectively locking workflows into a proprietary ecosystem incompatible with the emerging agentic era. In response, new tools like Claude Design adopt an "HTML and JS all the way down" approach, integrating directly with code to create a unified feedback loop where repositories feed AI agents. The author predicts a fork in the industry: one path toward honest, code-linked production tools, and another for unconstrained exploration environments similar to Photoshop. While criticizing this shift away from clean code, the author also urges competitors like Sketch to innovate with specific features (particle effects, mesh transforms) rather than resting on native capabilities, noting that Figma's format prevents its inclusion in necessary training data for AI agents.