はじめに
本記事は、以下の記事の 続編(追記) です:
🔗 https://qiita.com/Raymo-L/items/e8bb79bd9ccb8be49895
前編では、Terraform により構築した VPC / EC2 環境に対して、
踏み台サーバを用いず、SSM Session Manager 経由のみで EC2 に接続可能な状態を構築するところまでを扱いました。
本記事ではその延長として、
・EC2 を SSH を使わず SSM 管理下で運用するために必要だった修正点
・Nomad / Consul / Vault を server / client 構成で導入
・Consul / Nomad の Cluster Join が成立するところまでの確認
・検証過程で 実際に詰まったポイントと、その切り分け
を、実作業ベースで整理します。
検証のゴールと前提
検証のゴール
今回の検証におけるゴールは以下の 2 点です:
- EC2 を SSH なし・SSM 接続のみで管理できる状態にする
- Nomad / Consul / Vault を導入し、
server / client 間で Cluster Join が成立することを確認する
本検証では、アプリケーション実行基盤としての 前提となる基盤レイヤ(SSM 管理下 EC2 上での Nomad / Consul の Cluster Join) が成立するかどうかの確認を主目的としています。
前提条件
・Terraform により VPC / Subnet / EC2 / Security Group を構築済み
・EC2 は Private Subnet に配置
・インターネット Gateway / NAT Gateway は 未使用
・OS は Amazon Linux 系
・EC2 へのログインは SSM Session Manager のみ
構成概要
構成イメージ(検証時点)
EC2 × 3 台
・server × 1
・client × 2
・すべて Private Subnet
・接続は SSM のみ
・Nomad / Consul / Vault は EC2 へ直接インストール
[ SSM ]
|
[ server ] <---> [ client0 ]
\ /
<------> [ client1 ]
EC2 を SSM 管理下にするための修正点
前編の時点で SSM 接続自体は成功していたものの、
検証を進めるにつれて以下の課題が明確になりました
・SSM 接続はできるが、資材取得・検証が途中で詰まる
・Nomad Job 実行時に image pull が失敗する
・外部への通信が成立しない
原因
・EC2 は Private Subnet に配置されている
・NAT Gateway は存在しない
・SSM 接続に必要な VPC Endpoint のみが存在していた
実際に利用した VPC Endpoint
| サービス | 用途 |
|---|---|
| ssm | SSM Session Manager |
| ssmmessages | SSM 通信 |
| ec2messages | SSM 通信 |
| s3 | S3からの資材取得 |
これらは「SSM 接続できた=完成」ではなく、
“運用できる状態”とは別物であることを示していました。
学び
・SSM 接続に必要な Endpoint と、実運用に必要な Endpoint は違う
・特に S3 Endpoint は後から必ず欲しくなる
セキュリティグループ設計の方針
今回の検証で 最も時間を使ったのが Security Group (SG) 周りの設計でした。
当初の誤解:
・server 側に ingress を許可すれば通信できる
・client 側は egress all にしておけば問題ない
実際に発生した問題:
・Consul / Nomad が Join しない
・一方向では通信が成立しているように見えるが、反対方向からは見えない
・TCP のみ許可しており、UDP が不足していた
※Consul 公式文献にて、ポートリファレンスでは、同じポート番号でも TCP と UDP の双方が必要でした。
🔗 https://developer.hashicorp.com/consul/docs/reference/architecture/ports
つまりサーバ側の設定だけ開けても、UDP を使う gossip まで開いていないと他のノードとの通信が成立しない仕組みとなっています。
| プロトコル | Port | 用途 |
|---|---|---|
| TCP | 8300 | Consul サーバ RPC(サーバ ↔ サーバ・クライアント ↔ サーバ) |
| TCP/UDP | 8301 | LAN gossip(サーバ ↔ クライアント ↔ サーバ) |
| TCP/UDP | 8302 | WAN gossip |
| TCP | 8500 | HTTP API |
| TCP/UDP | 8600 | DNS |
特に 8301 は TCP だけでなく UDP も必要 であり、
Consul の Cluster Join やノード間の クラスタ健全性情報(メンバーの alive / failed 状態など) の共有に利用されています。
実際に必要だった対応:
・server ↔ client の 双方向通信
・TCP / UDP の 両方を明示的に許可
・同一 SG 内通信(self)も発生するため考慮が必要
対応として、
・server ↔ client の 双方向通信
・TCP / UDP の 両方を明示的に許可
・同一 SG 内通信(self)も発生するため考慮が必要
などの修正を行いました。
Nomad / Consul / Vault の導入
詳細な手順は割愛しますが、導入の考え方は以下の通りです。
共通作業
・バイナリを S3 経由で配置
・/usr/local/bin に配置
・systemd unit ファイルを作成し、サービスとして起動
server 側
Consul:server モード
Nomad:server モード
Vault:スタンドアロン構成(Cluster Join 対象外)
client 側
Consul:client モード
Nomad:client モード
詰まったポイントと切り分け
① Consul / Nomad が Join しない
原因
・SG の片方向通信のみ許可していた
・TCP のみ許可し、UDP を考慮していなかった
対応
・gossip 通信に必要な TCP / UDP の両方を許可
・server ↔ client の双方向通信を定義
② Nomad client が起動しない
エラー内容
failed creating alloc mounts dir: permission denied
Nomad service は起動するものの、client が ready にならない状態でした。
原因
・Nomad は systemd 上で nomad ユーザーとして実行される
・/var/lib/alloc_mounts の所有者・権限不足
対応
sudo mkdir -p /var/lib/alloc_mounts
sudo chown nomad:nomad /var/lib/alloc_mounts
Nomad は systemd 上では nomad ユーザーで動くことを見落としていた。
Consul Cluster Join 確認
確認時に混乱した点
Consul members が片側しか見えない:
・client 側では server が見える
・server 側では client が見えない
原因
・gossip 通信(8301/TCP/UDP)の片方向不足
・SG の定義が抜けていた
確認コマンド
consul members
最終的な確認結果
server alive
client0 alive
client1 alive
server / client 双方から同じ結果が確認できました。
Nomad Cluster Join の確認
server 側確認
nomad server status
Leader が存在することを確認
nomad node status
client0: ready
client1: ready
Job 実行による最終確認
検証用として hello.nomad を実行しました。
hello.nomad について
Nomad クラスタに client ノードが正しく参加し、
server からスケジューリングされたタスクが client 側で実行されることを確認するため、
exec ドライバを用いた最小構成のジョブとして使用しました。
job "hello" {
datacenters = ["dc1"]
group "example" {
task "hello" {
driver = "exec"
config {
command = "sh"
args = ["-c", "while true; do echo Hello Nomad; sleep 5; done"]
}
}
}
}
nomad job run hello.nomad
nomad alloc logs <alloc-id>
Hello Nomad
client ノードでジョブが実行されることを確認しました
Nomad / Consul の連携が成立していることを確認しました
検証結果まとめ
本検証では、以下を満たした時点で Cluster Join が成立したと判断しました。
・Consul members が server / client 双方で一致する
・Nomad server が leader として動作している
・Nomad client が ready 状態になる
・client ノード上でジョブが実行される
| 項目 | 結果 |
|---|---|
| SSM 管理下 EC2 接続 | OK |
| Consul Cluster Join | OK |
| Nomad Cluster Join | OK |
| server / client 分離 | OK |
| ジョブ実行 | OK |
補足:Nomad と Consul の連携について
本検証では、Nomad および Consul はそれぞれ server / client 構成で起動し、
Cluster Join が成立することまでを確認しています。
一方で、Nomad の設定ファイルやジョブ定義において
Consul への service 登録(service stanza)を用いた連携設定は 行っていません。
そのため、本記事時点では
Nomad と Consul はそれぞれ独立したクラスタとして動作している状態 であり、
アプリケーションのサービス検出やヘルスチェック連携までは未実施です。
振り返り・反省点
・HashiCorp 製品は通信仕様の理解がとても重要
・SG をとりあえず開けるような構成は後で必ず詰まる。SG設計の見積もりは慎重に。
・Nomad client は実行ユーザー視点でのディレクトリ設計が必須
・SSM + Private 構成は強力だが、Endpoint 設計を忘れると詰みが発生する
・VPC Endpoint を「SSM 用」としか考えていなかった
次に同じようなことを実施するなら
・SG Rule は最初から通信表を書いて設計
・VPC Endpoint は「後で足す前提」で余裕を持つ
おわりに
前編では SSM 接続、本記事では Cluster Join までを扱いました。
Terraform × SSM × Nomad / Consul というPrivate 構成特有の難しさが多い検証でしたが、
その分、実運用を見据えた多くの学びを得ることができました。