IPアドレス直書きの悪夢
最初の商用マイクロサービスプロジェクトを覚えています。5つのサービスから始め、application.propertiesファイルにIPアドレスをハードコードしても問題ないように見えました。しかし、50以上のサービスにスケールしたとき、すべてのデプロイが地雷原のようになりました。コンテナが再起動して新しいIPが割り当てられると、ダウンストリームのサービスがそれを見つけられず、システム全体の半分がダウンしてしまったのです。ネットワーク上の場所を手動で追跡することは、燃え尽き症候群とダウンタイムの元凶です。
私の実体験から言えば、これはマスターすべき不可欠なスキルの一つです。静的な設定から、動的で自己修復可能なアーキテクチャへと移行することです。ポッドが再起動するたびに設定ファイルを手動で更新しているなら、サービスディスカバリについて話し合う時が来ました。
根本原因:マイクロサービスで静的設定が失敗する理由
根本的な問題は、単にIPが変わることだけではありません。現代のDevOps環境において、インフラは「短命(エフェメラル)」であるということです。コンテナ、仮想マシン、サーバーレス関数は、破棄と再作成を繰り返すように設計されています。高速なCI/CDパイプラインを運用している場合、サービスの「場所」(IPとポート)は常に変動しています。
中央集権的なレジストリがなければ、2つの大きな問題が発生します:
- 設定の乖離(コンフィギュレーション・ドリフト): 異なるサービスが、他のサービスに関する古い情報を保持してしまいます。
- ゾンビサービス: サービスが停止していても設定リストに残っていることがあり、接続タイムアウトや連鎖的な障害を引き起こします。
HashiCorp Consulとは?
Consulは、あらゆるランタイムプラットフォームやパブリック・プライベートクラウド上で、サービス間の接続とセキュリティを確保するためのマルチクラウド・サービスネットワーキングプラットフォームです。主に以下の3つの重要な機能を提供します:
- サービスディスカバリ: Consulのクライアントはサービスを登録でき、他のクライアントはConsulを使用して特定のサービスの提供者を検出できます。
- ヘルスチェック: Consulは登録されたサービスの健全性を監視し、異常のあるノードへのトラフィック送信を防ぎます。
- KVストア: 実行時にサービスが問い合わせ可能な、動的設定のための中央集権的な保存場所です。
実践:最初のConsulノードをセットアップする
ローカルでの開発やテストには、Dockerを使用するのが最も簡単な方法です。このコマンドは、開発モードで単一のConsulエージェントを起動します:
docker run -d --name=consul-node -p 8500:8500 consul:latest
実行されると、http://localhost:8500でUIにアクセスできます。Consulクラスターのネットワークをセットアップする際、IP範囲の計画が必要になることがよくあります。ToolCraftのSubnet Calculatorは、CIDR表記や使用可能なホスト範囲の計算に便利です。データを追跡しないクライアントサイドのツールなので、内部ネットワークの設計をするときにも安心です。
マイクロサービスの登録
サービスを登録するには、HTTP APIまたは設定ファイルを使用します。例えば、192.168.1.50のポート8080で実行されている「inventory-service」があるとします。inventory.jsonという名前のJSONファイルを作成します:
{
"service": {
"name": "inventory-service",
"tags": ["v1", "production"],
"address": "192.168.1.50",
"port": 8080,
"check": {
"http": "http://192.168.1.50:8080/health",
"interval": "10s"
}
}
}
私はKubernetes用のYAMLとConsul API用のJSONを頻繁に行き来します。内部サービス名を保存する可能性のある怪しいオンラインコンバーターを使う代わりに、YAML ↔ JSON Converterを使っています。100%ブラウザで動作するため、サービスアーキテクチャのプライバシーが保たれることがわかっています。
ConsulエージェントのAPIにこのJSONを送信して、サービスを登録します:
curl --request PUT --data @inventory.json http://localhost:8500/v1/agent/service/register
自動ヘルスチェックの威力
上記のJSONにあるcheckブロックが魔法の鍵です。Consulは10秒ごとにその/healthエンドポイントをポーリングします。サービスが500エラーを返したり、応答がなかったりした場合、Consulはそれを「クリティカル」としてマークします。別のサービスがConsulに「inventory-serviceはどこ?」と尋ねたとき、Consulは正常なインスタンスのIPのみを返します。これにより、設定を手動で変更することなく、フェイルオーバーが事実上自動化されます。
K/Vストアによる動的構成
フィーチャーフラグやデータベース接続文字列をハードコードすることは、IPをハードコードするのと同じくらい危険です。Consulのキー/バリューストアを使用すると、再起動なしでアプリケーションの動作を変更できます。次のように設定値を保存できます:
curl --request PUT --data "true" http://localhost:8500/v1/kv/config/inventory/maintenance_mode
アプリケーションはこのエンドポイントをポーリングするか、consul-templateのようなツールを使用して、Consulの値が変更されるたびにローカルの設定ファイルを自動的に更新できます。これは、メンテナンスページの切り替えや、クラスタ全体のログレベルの調整を数秒で行うのに非常に強力です。
コードへの実践的な統合
ほとんどのモダンなフレームワークはConsulをネイティブにサポートしています。Spring Bootを使用している場合は、spring-cloud-starter-consul-discovery依存関係を追加するだけでほぼ完了です。Python開発者の場合、APIの操作にはpython-consulライブラリが標準的です。
Pythonでサービスアドレスを取得する簡単な例を次に示します:
import consul
c = consul.Consul()
index, data = c.health.service('inventory-service', passing=True)
for item in data:
# 正常なインスタンスの場所を表示
print(f"正常なインスタンスが見つかりました: {item['Service']['Address']}:{item['Service']['Port']}")
まとめ
HashiCorp Consulに切り替えたことで、私のインフラ管理方法は一変しました。サービスの場所を追跡する負担が、エンジニアからシステム自体に移ります。サービスディスカバリ、自動ヘルスチェック、動的構成を組み合わせることで、分散環境で避けられない失敗に対処できるシステムを構築できます。
まずは小さく始めてみてください。一つのサービスを登録し、ヘルスチェックを追加して、IPアドレスを心配しなくなるだけでアプリケーションロジックがどれほどクリーンになるかを確認してください。システムが成長するにつれ、マイクロサービスの状態に関する「信頼できる唯一の情報源(Single Source of Truth)」を持つことは、単なる利便性ではなく、DevOpsの世界で生き残るための必需品であることに気づくはずです。

