はじめに
Splunk Enterpriseの分散構成を検証するために、複数台のサーバーやネットワークを一から用意するのは大変です。検証条件によっては、AWS上にEC2、Application Load Balancer(ALB)などのリソースを準備する必要もあります。
CloudFormationテンプレートを使えば、こうした定型的な分散構成のAWSリソースを数分で構築できますし、生成AIエージェントを利用して検証条件に合わせて編集することも容易です。
今回はSplunkをインストールする前段として、CloudFormationのネストスタックを使ってAWSリソースを構築しました。本記事が同様の検証環境を準備する際の参考になれば、ぜひ活用してください。
本記事で利用するテンプレート
本記事では、次の公開用テンプレートを使用します。
PUB-splunk-distributed-deployment-on-aws
このテンプレートは検証環境用のひな形です。利用時は、自身の要件に合わせてネットワーク構成、アクセス制御、インスタンスタイプなどを確認・変更してください。
本テンプレートはAWS CLIとAWS MCP Serverを設定した生成AIエージェントを用い、仕様駆動開発の手法で作成しました。具体的な開発手順は、別の記事で紹介する予定です。
前提知識
- VPC、EC2、IAM、ALB、Route 53の基本的な役割を理解している
- AWS CLIのプロファイルを設定できる
- YAML形式のCloudFormationテンプレートを読める
構築する環境
本記事の手順では、東京リージョンにSplunk分散構成の土台となるAWSリソースを構築します。CloudFormationが作成する範囲は、ネットワーク、EC2、IAM、ALB、Route 53です。
| 項目 | 内容 |
|---|---|
| AWSリージョン | ap-northeast-1 |
| EC2 | Amazon Linux 2023、7台 |
| CloudFormation | 親スタック1個、子スタック8個 |
| 主な構築対象 | VPC、EC2、IAM、ALB、Route 53 |
| 構築対象外 | Splunk Enterpriseのインストールとクラスタ設定 |
CloudFormationで構築するAWSリソース
検証環境では、Splunk Enterpriseを次の7台へ配置することを想定しています。
| 台数 | ホストの役割 | Splunkでの役割 | 配置 |
|---|---|---|---|
| 2 | Search Head | Search Head Cluster member | 2つのパブリックサブネット |
| 1 | 管理サーバー | deployer、license manager | プライベートサブネット |
| 1 | Cluster Manager | Indexer Cluster manager node | プライベートサブネット |
| 3 | Indexer | Indexer Cluster peer node | プライベートサブネット |
CloudFormationが担当するのは、Splunkを導入する前のAWS基盤です。
- VPC、サブネット、Internet Gateway、NAT Gateway、ルートテーブル
- Security Group
- EC2、IAMロール、インスタンスプロファイル
- 公開用ALB、管理用ALB、target group、listener
- Route 53の公開レコード、プライベートホストゾーン、内部レコード
- EC2のホスト名と役割を示す最小限の初期設定
- Systems Managerから管理するためのIAM権限
Splunk Enterpriseのインストール、ライセンス設定、Indexer Cluster、Search Head Clusterの設定はCloudFormationの外で実施します。基盤作成とSplunk構築を分けることで、CloudFormationの成功条件を「AWSリソースとOSの初期化が完了した状態」に限定できます。
この記事の2台のSearch Headは学習・機能確認用です。可用性を備えたSearch Head Clusterの構成要件を示すものではありません。
親スタックと子スタックの責務
親テンプレートmain.yamlは、AWSリソースを直接定義せず、8個の子スタックをまとめる役割を持ちます。
| テンプレート | 主な責務 |
|---|---|
vpc-network.yaml |
VPC、サブネット、ルート、Internet Gateway、NAT Gateway |
security-groups.yaml |
ALBとSplunkノード間の通信制御 |
iam-roles.yaml |
EC2用IAMロールとインスタンスプロファイル |
ec2-shc.yaml |
Search Head用EC2 2台と初期化処理 |
ec2-private.yaml |
管理サーバー、Cluster Manager、Indexer 3台 |
alb.yaml |
Search HeadとHEC向けの公開用ALB |
admin-alb.yaml |
管理用Splunk Web向けALB |
route53.yaml |
公開Aliasレコード、プライベートホストゾーン、内部Aレコード |
依存関係を簡略化すると、次のようになります。
CloudFormationでは、子スタックをAWS::CloudFormation::Stackリソースとして定義します。次の例では、Networkスタックが出力したVPC IDをSecurity Groupsスタックへ渡しています。
Resources:
Network:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub >-
https://${TemplateBucket}.s3.${AWS::Region}.amazonaws.com/${TemplatePrefix}/vpc-network.yaml
Parameters:
Environment: !Ref Environment
VpcCidr: !Ref VpcCidr
SecurityGroups:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub >-
https://${TemplateBucket}.s3.${AWS::Region}.amazonaws.com/${TemplatePrefix}/security-groups.yaml
Parameters:
Environment: !Ref Environment
VpcId: !GetAtt Network.Outputs.VpcId
Networkスタック側では、後続スタックが必要とする値をOutputsへ定義します。
Outputs:
VpcId:
Value: !Ref Vpc
PublicSubnetAId:
Value: !Ref PublicSubnetA
PrivateSubnetAId:
Value: !Ref PrivateSubnetA
親スタックは!GetAtt Network.Outputs.VpcIdの形式で値を取得します。明示的なDependsOnを書かなくても、この参照関係によってNetworkスタックの出力が利用可能になってから後続スタックが作成されます。
デプロイの準備
作業端末にはAWS CLIをインストールし、対象AWSアカウントを操作できるプロファイルを設定しておきます。以降のコマンド例では、プロファイル名をsplunk-deploy、リージョンをap-northeast-1とします。利用する環境に合わせて読み替えてください。
本環境では検証用として
splunk-deployにAdministratorAccess権限を与えています。
1. テンプレートを取得する
公開リポジトリを取得し、リポジトリのルートディレクトリへ移動します。
git clone https://github.com/YamaguchiMasateru/PUB-splunk-distributed-deployment-on-aws.git
cd PUB-splunk-distributed-deployment-on-aws
以降のコマンドは、このディレクトリで実行します。
2. 必要な外部リソースを準備する
この構成では、次のリソースをスタック作成前に準備します。
- 子テンプレートを格納するS3バケット
- ALBで使用する証明書
- Route 53の公開ホストゾーン
- 各EC2で使用するAmazon Linux 2023のAMI ID
- 管理画面とHTTP Event Collector(HEC)への接続を許可するCIDR(テスト用)
S3バケット、Route 53公開ホストゾーン、ACM証明書は、このCloudFormationスタックからは作成されません。各リソースを準備したうえで、その識別子を次の手順のparameters.jsonへ指定します。
注意: この構成では、EC2、ALB、NAT Gateway、Route 53などの料金が発生します。利用前に料金とサービスクォータを確認してください。
注意: ALBで使用する通常のACMパブリック証明書は、追加料金なしで利用できます。一方、エクスポート可能な証明書として発行すると、発行時と更新時に料金が発生します。2026年8月時点では、ワイルドカード名1件につき79 USDです。証明書をALBでのみ使用する場合はワイルドカードもエクスポートも必要はありませんが、証明書を各Splunkインスタンス配布用として利用する場合、ワイルドカードやエクスポートが視野にはいるので、その際は利用料金を考慮ください。コスト優先で作る場合は Let's Encryptで証明書発行 -> ACMで取り込み をお勧めします。
3. 環境に合わせてパラメーターを準備する
入力例をコピーして、デプロイに使用するparameters.jsonを作成します。
cp cloudformation/parameters.example.json cloudformation/parameters.json
作成したファイルの値を、利用するAWS環境に合わせて変更します。次は記述形式を示すサンプルであり、このままではデプロイできません。
[
{
"ParameterKey": "Environment",
"ParameterValue": "dev"
},
{
"ParameterKey": "TemplateBucket",
"ParameterValue": "splunk-templates-123456789012-ap-northeast-1"
},
{
"ParameterKey": "Shc1AmiId",
"ParameterValue": "ami-xxxxxxxxxxxxxxxxx"
},
{
"ParameterKey": "PublicHostedZoneId",
"ParameterValue": "ZXXXXXXXXXXXXXXXXXXXX"
},
{
"ParameterKey": "AlbRecordName",
"ParameterValue": "splunk.example.com"
},
{
"ParameterKey": "CertificateArn",
"ParameterValue": "arn:aws:acm:ap-northeast-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
{
"ParameterKey": "ManagementSourceCidr1",
"ParameterValue": "203.0.113.0/24"
}
]
実際には7台分のAMI ID、公開レコード名、HECの許可元CIDRなども指定します。空文字を許容する任意パラメーターと、必須パラメーターを区別して確認してください。
注意:
parameters.jsonにはアカウントID、ドメイン、証明書ARN、接続元CIDRなどが含まれます。公開リポジトリの.gitignoreでは追跡対象外にしていますが、コミット前にもGitの状態を確認してください。
4. テンプレートを検証する
子テンプレートをS3へアップロードする前に、CloudFormationで構文を検証します。次のコマンドは、公開用リポジトリのcloudformation直下にあるYAMLファイルを順番に検証します。
for template in cloudformation/*.yaml; do
echo "Validating: ${template}"
aws cloudformation validate-template \
--template-body "file://${template}" \
--profile splunk-deploy \
--region ap-northeast-1
done
コマンドが各テンプレートのDescriptionやParametersを返し、エラーが表示されなければ、CloudFormationがテンプレートを読み取れています。
validate-templateはテンプレートの構文を検証するコマンドです。実際のパラメーター値、権限、クォータ、参照先リソース、リソース間の実行時の整合性まで保証するものではありません。
5. 子テンプレートをS3へ配置する
親スタックのTemplateURLから参照できるよう、子テンプレートをS3へアップロードします。
aws s3 sync cloudformation/ \
s3://splunk-templates-123456789012-ap-northeast-1/Cfn_Template/ \
--exclude "main.yaml" \
--exclude "parameters.json" \
--exclude "parameters.example.json" \
--exclude "README.md" \
--profile splunk-deploy \
--region ap-northeast-1
期待する結果は、親テンプレートのTemplateURLと同じキーへ8個の子テンプレートが配置されることです。バケットを公開する必要はありませんが、CloudFormationを実行する主体がテンプレートを参照できる権限は必要です。
親スタックを作成する
次のコマンドで、ローカルのmain.yamlを親テンプレートとしてスタック作成を開始します。
aws cloudformation create-stack \
--stack-name splunk-cluster \
--template-body file://cloudformation/main.yaml \
--parameters file://cloudformation/parameters.json \
--capabilities CAPABILITY_NAMED_IAM \
--profile splunk-deploy \
--region ap-northeast-1
この構成では名前を指定したIAMロールとインスタンスプロファイルを作成するため、CAPABILITY_NAMED_IAMによる確認が必要です。コマンドがStack IDを返しても、リソース作成はバックグラウンドで継続しています。
作成完了まで待機する場合は、次のコマンドを使用します。
aws cloudformation wait stack-create-complete \
--stack-name splunk-cluster \
--profile splunk-deploy \
--region ap-northeast-1
待機コマンドに出力はありません。終了コードが0になったあと、describe-stacksで状態を確認します。
aws cloudformation describe-stacks \
--stack-name splunk-cluster \
--query 'Stacks[0].[StackName,StackStatus]' \
--output table \
--profile splunk-deploy \
--region ap-northeast-1
期待する状態はCREATE_COMPLETEです。失敗した場合は、スタックイベントを新しい順に確認します。
aws cloudformation describe-stack-events \
--stack-name splunk-cluster \
--query 'StackEvents[].[Timestamp,LogicalResourceId,ResourceStatus,ResourceStatusReason]' \
--output table \
--profile splunk-deploy \
--region ap-northeast-1
親スタックだけで原因が分からない場合は、失敗した子スタックのイベントも確認します。
EC2の初期化完了をCloudFormationへ伝える
EC2リソースにはAWS::CloudFormation::Init、CreationPolicy、User Dataを組み合わせています。次はSearch Head用EC2の要点を抜粋した例です。
Resources:
Shc1Instance:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Count: 1
Timeout: PT30M
Metadata:
AWS::CloudFormation::Init:
config:
files:
/etc/splunk-role:
content: |
ROLE=shc-member
commands:
01_hostname:
command: hostnamectl set-hostname shc-1.example.com
Properties:
UserData:
Fn::Base64: !Sub |
#!/bin/bash
dnf install -y aws-cfn-bootstrap
/opt/aws/bin/cfn-init -v \
--stack ${AWS::StackName} \
--resource Shc1Instance \
--region ${AWS::Region}
init_exit=$?
/opt/aws/bin/cfn-signal -e "${!init_exit}" \
--stack ${AWS::StackName} \
--resource Shc1Instance \
--region ${AWS::Region}
exit "${!init_exit}"
それぞれの役割は次のとおりです。
| 要素 | 役割 |
|---|---|
AWS::CloudFormation::Init |
EC2へ適用するファイルやコマンドをMetadataへ定義する |
cfn-init |
Metadataを読み取り、EC2上で初期化処理を実行する |
cfn-signal |
初期化コマンドの終了コードをCloudFormationへ送る |
CreationPolicy |
指定数の成功シグナルを受け取るまでリソースの作成完了を待つ |
CreationPolicyを指定しない場合、EC2インスタンスが起動状態になった時点でCloudFormation上の作成が完了し、OS内の初期化失敗を見逃す可能性があります。この構成ではEC2ごとに1件の成功シグナルを要求し、30分でタイムアウトします。
今回の成功条件に含めるのは、ホスト名、/etc/hostsの自己エントリ、役割ファイルなどの最小限のOS設定です。Splunk Enterpriseのインストールやクラスタの健全性は含めません。
作成後の確認
CloudFormationのネストスタックを確認する
親スタック配下のスタックリソースを確認します。
aws cloudformation list-stack-resources \
--stack-name splunk-cluster \
--query 'StackResourceSummaries[?ResourceType==`AWS::CloudFormation::Stack`].[LogicalResourceId,ResourceStatus]' \
--output table \
--profile splunk-deploy \
--region ap-northeast-1
期待する結果は、8個の子スタックがCREATE_COMPLETEになっていることです。
EC2が7台作成されたことを確認する
CloudFormationが付与するスタック名タグを使って、対象EC2を絞り込みます。
aws ec2 describe-instances \
--filters \
Name=tag:aws:cloudformation:stack-name,Values='splunk-cluster-*' \
Name=instance-state-name,Values=pending,running,stopping,stopped \
--query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`].Value|[0],State.Name]' \
--output table \
--profile splunk-deploy \
--region ap-northeast-1
親スタックから作成された子スタック名には一意な文字列が付くため、ここでは前方一致を使用します。期待する結果は7台が表示されることです。
Systems Managerの管理対象を確認する
対象EC2がSystems Managerから認識されているかを確認します。
aws ssm describe-instance-information \
--filters Key=tag-key,Values=SplunkRole \
--query 'InstanceInformationList[].[InstanceId,PingStatus,PlatformName]' \
--output table \
--profile splunk-deploy \
--region ap-northeast-1
各EC2には役割を示すSplunkRoleタグを付けています。期待する結果は、7台が表示され、PingStatusがOnlineになることです。同じタグを持つ別環境が存在する場合は、そのノードも表示されるため、Instance IDとNameタグを照合します。表示されない場合は、SSM Agent、IAMインスタンスプロファイル、外向きのHTTPS通信を確認します。
Run Commandで7台との接続を確認する
managed nodeとして表示されることを確認したら、タグを指定して7台へ接続確認用のコマンドを送信します。ここではSplunkをインストールせず、ホスト名とCloudFormationが配置した役割ファイルだけを取得します。
command_id=$(aws ssm send-command \
--document-name AWS-RunShellScript \
--targets 'Key=tag:SplunkRole,Values=shc-member,mgmt,cluster-manager,indexer-peer' \
--parameters 'commands=["hostname","cat /etc/splunk-role"]' \
--comment "Verify SSM connectivity before installing Splunk" \
--query 'Command.CommandId' \
--output text \
--profile splunk-deploy \
--region ap-northeast-1)
実行結果を確認します。
aws ssm list-command-invocations \
--command-id "${command_id}" \
--details \
--query 'CommandInvocations[].[InstanceId,Status,CommandPlugins[0].Output]' \
--output table \
--profile splunk-deploy \
--region ap-northeast-1
コマンドを送信した直後はPendingまたはInProgressと表示されることがあります。その場合は、同じ確認コマンドを時間を置いて再実行します。期待する結果は、7台すべてのStatusがSuccessとなり、各ホスト名とROLEが表示されることです。この確認を通過した環境を、後続記事のSplunk一括インストールで使用します。
まとめ
CloudFormationのネストスタックを使うと、ネットワーク、IAM、EC2、ALB、DNSの責務を分けながら、親スタックから一つのシステムとして管理できます。
今回のポイントは次のとおりです。
- 子スタックはAWSリソースの種類や変更単位で分割する
- 子スタックの
Outputsを親スタックがGetAttで取得し、後続スタックへ渡す -
cfn-initとcfn-signalをCreationPolicyと組み合わせ、OS初期化までをCloudFormationの成功条件にする - Splunkのインストールとクラスタ設定はAWS基盤の作成から分離する
- Systems Managerで7台が
OnlineになるところまでをAWS基盤の確認範囲とする
次回は、ここで構築したEC2にSplunkを一括インストール、一括初期設定を進めていきます。
参考資料
- Split a template into reusable pieces using nested stacks - AWS CloudFormation(参照日: 2026-08-12)
- AWS::CloudFormation::Stack - AWS CloudFormation(参照日: 2026-08-12)
- CreationPolicy attribute - AWS CloudFormation(参照日: 2026-08-12)
- cfn-init - AWS CloudFormation(参照日: 2026-08-12)
- cfn-signal - AWS CloudFormation(参照日: 2026-08-12)
- validate-template - AWS CLI Command Reference(参照日: 2026-08-12)
- create-stack - AWS CLI Command Reference(参照日: 2026-08-12)
- send-command - AWS CLI Command Reference(参照日: 2026-08-12)
- list-command-invocations - AWS CLI Command Reference(参照日: 2026-08-12)