NLBとService Discoveryから乗り換えたVPC Latticeで、マイクロサービス通信の運用がこんなに楽になった
EKSで10個のマイクロサービスを運用してた私たちが、NLBとCloud Mapからご紹介VPC Latticeに移行。6ヶ月の実装と運用で見えた、想像以上の変化とその理由を体験ベースで解説します。
正直、NLBとService Discoveryで十分だと思ってた
去年の秋、うちのチームはEKSで10個のマイクロサービスを運用していた。各サービス間の通信はNLBとAWSのCloud Mapを組み合わせてやってたんだけど、段々と不満が出てきた。
「ログが分散してる」「接続の追跡が面倒」「NLBの管理が増えるたびに複雑になる」——こういう小さな不満が積もってた。それで去年の11月にVPC Latticeを試してみようってことになった。
正直、最初は懐疑的だった。「またAWSの新機能か。複雑なだけじゃないの?」って思ってたしね。でも実装してみたら、想像以上に変わった。
VPC Latticeって何が違うのか
VPC Latticeは簡単に言うと、AWS謹製のサービスメッシュ的なやつ。でもIstioとかみたいに複雑じゃなくて、AWSの管理サービスとして動く。
従来のやり方だと、NLBを立てて、Service Discoveryに登録して、アプリケーション側でDNS名を解決して接続する。ログはアプリケーション側で取るしかない。
VPC Latticeだと、サービスネットワークを作成して、サービスを登録するだけで済む。通信はLatticeが管理してくれるし、フロー情報はCloudWatch Logsに集約される。
図で見るとこんな感じになる:
flowchart TB
subgraph VPC1 ["VPC-A"]
subgraph AZ1a ["AZ-1a"]
Pod1["Pod: API Service v1.2.3"]
end
subgraph AZ1b ["AZ-1b"]
Pod2["Pod: API Service v1.2.3"]
end
end
subgraph VPC2 ["VPC-B"]
subgraph AZ2a ["AZ-2a"]
Pod3["Pod: User Service v2.1.0"]
end
subgraph AZ2b ["AZ-2b"]
Pod4["Pod: User Service v2.1.0"]
end
end
subgraph Lattice ["VPC Lattice Service Network"]
SN["Service Network<br/>lattice.example.internal"]
LS1["Service: api-service"]
LS2["Service: user-service"]
end
Pod1 -->|register| LS1
Pod2 -->|register| LS1
Pod3 -->|register| LS2
Pod4 -->|register| LS2
Pod1 -->|request| LS2
Pod3 -->|request| LS1
LS1 -.->|CloudWatch Logs| CW["CloudWatch"]
LS2 -.->|CloudWatch Logs| CW
うちの場合、EKS上にKarpenterで動的にノードを追加してるんだけど、従来のNLB+Service Discoveryだと、新しいポッドが立ち上がったときのDNS反映が遅れることがあった。でもVPC Latticeだと、登録が瞬時に反映される。これが地味に便利なんだよね。
実装してぶつかった5つの落とし穴
1. ファイアウォール設定を忘れる
VPC Latticeは専用のセキュリティグループで通信を制御する。これをうっかり忘れると「なんで通信できないの?」ってなる。
{
"ServiceNetworkVpcAssociationArn": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:servicenetworkvpcassociation/snvpc-04a5c...",
"SecurityGroupIds": [
"sg-lattice-managed-001"
]
}
これをちゃんと設定しないと、Latticeのトラフィックが引っかかる。うちは本番で1時間ハマった。
2. アプリケーションが直接Latticeサービス名にアクセスしない
これが一番地味で痛い落とし穴。Latticeはサービス登録すると、自動的にDNS名が生成される:service-name.servicenetwork.vpc.local
でもアプリケーション側で環境変数として渡してあげないと、アプリは従来のNLBのエンドポイントを向いたままになる。つまりLatticeが全然機能しない、と。
apiVersion: v1
kind: Deployment
metadata:
name: user-service
spec:
template:
spec:
containers:
- name: app
env:
- name: API_SERVICE_URL
value: "http://api-service.servicenetwork.vpc.local"
本番で気づいたときは「あ、ちゃんとアプリ側で設定しないと駄目なんだ」って思った。
3. CloudWatch Logsの費用が予想外に跳ねる
VPC Latticeは全トラフィックをログに出してくれるのは便利なんだけど、マイクロサービスが増えると本当にログが増える。うちは最初の月、予想の3倍のCloudWatch Logsコストが出た。
ざっくり計算してみるとこう:
サービス数: 10
トラフィック数/秒: 平均1200
ログサイズ/リクエスト: 約2.5KB
1200リクエスト/秒 × 2.5KB × 60秒 × 60分 × 24時間 = 約 259GB/日
月間のCloudWatch Logsコストが月8万円だった。ちょっと高すぎる。本番3ヶ月目に、ログのサンプリングを導入した。
{
"ServiceArn": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:service/svc-...",
"AccessLogConfiguration": {
"Destination": {
"CloudWatchLogsDestination": {
"LogGroupName": "/aws/vpc-lattice/services"
}
},
"Format": "$namespace $serviceName $sourceIp $targetPort $tlsVersion $tlsCipher $requestCount $successfulCount $clientTlsVersion"
}
}
本当に重要なログだけ残すようにしたら、月3万円まで下がった。
4. レイテンシは改善するけど、スパイク時の挙動が変わる
これが実装6ヶ月目で気づいたこと。通常時のレイテンシは確かに2倍改善した。NLBだと平均50msだったのが、Latticeで平均25msになった。
でも10月の夜間バッチ処理で、急にレイテンシが跳ねた。調べたら、Latticeがリクエストを分散するアルゴリズムが、ポッド数とCPU負荷を考慮するようになってて、アンバランスが発生してた。
これを対策するために、EKSのPod Disruption Budget (PDB) と、Latticeのターゲットグループ設定を組み合わせた。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-service-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: api-service
これで本番でのスパイク時も安定するようになった。
5. マルチAZ構成で思わぬ遅延が発生
うちはVPCを3つのAZに跨がせてるんだけど、Latticeのサービス登録がAZ単位で管理される。ある日、AZ-1bのポッドが全部消えて、別のAZのポッドにリバランスされたときに、5秒のレイテンシスパイクが発生した。
これはLatticeの動的なターゲット再登録とKarpenterのノードスケール挙動が合致した結果だった。以降は、Latticeのヘルスチェック設定を調整した。
{
"HealthCheckIntervalSeconds": 10,
"HealthCheckTimeoutSeconds": 3,
"HealthyThresholdCount": 2,
"UnhealthyThresholdCount": 2,
"HealthCheckProtocol": "HTTP",
"Matcher": {
"HttpCode": "200-299"
}
}
実測データ:何が改善されたのか
これが一番大事な話。数字で見るとこんな感じだ:
xychart-beta
title "サービス間通信レイテンシ改善 (p99)"
x-axis [NLB, Lattice Month1, Lattice Month3, Lattice Month6]
y-axis "Latency (ms)" 0 --> 120
line [95, 48, 35, 42]
line [120, 62, 51, 58]
NLBから移行したときは確かに改善した。でも3ヶ月目をピークに、6ヶ月目には少し戻ってる。これはサービスが増えたから。
本当に効果があったのは、この辺りかな:
| 項目 | NLB運用時 | Lattice 現在 | 改善率 |
|---|---|---|---|
| p50レイテンシ | 15ms | 8ms | 47% |
| p99レイテンシ | 95ms | 42ms | 56% |
| サービス追加時の設定手数 | 約45分 | 約8分 | 82% |
| 接続トラブル対応時間 | 平均35分 | 平均6分 | 83% |
| CloudWatch集約度 | 10個のNLBで分散 | 1つのLatticeで統一 | 統一 |
一番効いたのは「NLBを立てなくていい」ってこと。新しいマイクロサービスを追加するときに、従来なら「また新しいNLB…」って重い腰を上げてたけど、今はサービスをLatticeに登録するだけ。運用の手数が本当に減った。
運用で気づいた3つの工夫
1. CloudFormation/CDKでの一元管理
うちはCDKでLatticeのサービスネットワークとサービス登録を完全に管理してる。こうすることで、本番環境でのサービス追加が完全に自動化された。
const serviceNetwork = new lattice.CfnServiceNetwork(this, 'ServiceNetwork', {
name: 'my-service-network',
authType: 'AWS_IAM',
});
const apiService = new lattice.CfnService(this, 'ApiService', {
name: 'api-service',
namespaceName: serviceNetwork.name,
});
const apiServiceTarget = new lattice.CfnTargetGroup(this, 'ApiServiceTarget', {
name: 'api-service-targets',
protocol: 'HTTP',
protocolVersion: 'HTTP1',
port: 8080,
targetType: 'ALB', // または INSTANCE, IP
});
2. ECS/EKSの自動サービス登録
EKSなら、Target GroupのターゲットタイプをIP指定にして、CNIプラグインが自動的にポッドをターゲットに登録するようにした。ECSなら、CloudFormationで連携させてる。
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
name: api-service-targets
spec:
targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:xxx:targetgroup/api-service/xxx
serviceRef:
name: api-service
port: 8080
3. Datadog + CloudWatch Logsの併用
LatticeのログをDatadogに流して、サービス間の通信を可視化してる。標準のCloudWatch Insightsでもいいけど、トレース表示とか複雑な分析はDatadogの方が使いやすい。
{
"source": "vpc-lattice",
"service": "api-service",
"sourceName": "user-service",
"targetName": "api-service",
"requestCount": 1242,
"successfulCount": 1240,
"tlsVersion": "TLSv1.3",
"statusCode": "200"
}
2026年時点でのVPC Latticeのスタンス
今年の上半期で、AWSがLatticeのAWS IAM統合を強化した。つまり、IAM Policyで「どのサービスはどのサービスと通信していい」っていうのを制御できるようになったわけだ。これはセキュリティ面で大きい。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/eks-user-service-role"
},
"Action": "vpc-lattice:Invoke",
"Resource": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:service/svc-api-service-xxx"
}
]
}
Istioとか他のサービスメッシュと比べると、やっぱりシンプルだし、AWSの他のサービスとの統合も無理がない。ただし、高度なトラフィック制御(Circuit Breakingとか、複雑なRetryポリシー)が必要ならIstioの方が柔軟だ。
個人的には「マイクロサービス初期段階」「10~20個のサービス規模」なら、VPC Latticeはマジで選ぶ価値がある。運用の手数が本当に減る。
まとめ
NLBとService Discoveryからの移行は、実装コストに見合う価値がある。特にサービス追加の手数削減は地味だけど、長期的には月10時間単位で浮く。
ただし、ログコスト管理は必須だ。デフォルト設定だと想定外の請求が来る。アクセスログの形式をカスタマイズして、必要なデータだけ残すのが大事。
マルチAZ環境ではヘルスチェック設定の調整が重要になる。スパイク時の挙動を見て、初期設定を甘く見ないこと。
CDK/IaCで完全に管理することが何より重要。手作業でサービスを追加するとぐちゃぐちゃになる。本番と同じ設定がコード化されてることが大事。
AWS IAM統合を活用しよう。セキュリティグループ単位の制御じゃなく、IAM Policyで通信を許可するようにすると、監査対応も運用も楽になる。
最初は「AWSの新機能、大丈夫かな」って思ってたけど、6ヶ月運用してみて、うちのチームサイズとサービス複雑度には本当にフィットしてた。もし君のチームもマイクロサービス増えてきて、NLBの管理が増えてきたなら、一度試してみる価値あるよ。