この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
よく訓練されたアップル信者、都元です。
最近ブログにAWSネタが少ないなぁ。|o゚д゚)
— よこたさとし (@sato_shi) October 5, 2013
ハイ! AWSチームなのにSpring Frameworkネタばっか書いてんじゃねえよ、ということで、都元の愛するCloudFromationを使ってfluentdサーバを立ててみました。
CloudFormationの流儀
CloudFormationのテンプレートは汎用的に越した事はありません。その前提で。
EC2において、「何かをインストールしたサーバ」をCloudFormationで構築したい場合、ぱっと思いつくのは「構築済みのAMIを用意する」ことでしょうか。しかし、独自AMIのメンテナンスというのは意外と大変なので、出来れば「素のAmazon Linuxから、自動的にサーバが構築される」といった仕組みを用意したいものです。素のAmazon Linuxは公開されたAMIですので、アカウントに依存しないポータビリティが実現できる、というメリットも大きいです。
そんな望みに応えるCloudFormationの機能として、以前CloudFormationのヘルパースクリプトcfn-initによるインスタンスの初期化というものをご紹介しました。今回、この仕組みを使って、VPC環境内にfluentdサーバを立ててみましょう。
fluentdのテンプレート
テンプレート全体はgistに置いておきましたので、必要に応じて参照してください。ここでは重要な部分を抜粋して解説します。
ログの格納先S3バケット
fluentdに送られて来たログデータは、fluent-plugin-s3を使ってS3バケットに書き出すことにしましょう。その辺りの詳細は、Amazon LinuxにFluentdをインストールしてS3とMongoDB連携するというエントリで紹介されています。
CloudFormationで、まずログを出力するためのS3バケットを定義しましょう。あまりにも簡単な記述ですが、"DeletionPolicy" : "Retain"となっているのがキモです。というのも、CloudFormationは、スタックを削除する際に、基本的に関連リソースを全て削除してしまいます。つまり、ログが豊富に溜まったS3バケットも、デフォルトでは削除されてしまうのです。ログ用のバケットはそのようなことにならないように、スタックの撤収時であっても削除しない、というのがこの設定です。
"LogBucket" : {
"Type" : "AWS::S3::Bucket",
"DeletionPolicy" : "Retain"
},
2つのconfigSet
続いて、FluentdInstanceのcfn-init設定を見てください。configSetsという見慣れないプロパティがあります。
通常、AWS::CloudFormation::Initの直下には1つのconfigを配置し、その下にfiles, commands, packages, services等 *1の設定を記述していきます。
これらの設定は、通常packages, files, servicesの順で処理されます *2。しかし今回の場合、filesで/etc/yum.repos.d/td.repoファイルを配置してからpackagesによるtd-agentのインストールを行い、その後でまた、filesで/etc/td-agent/td-agent.confを書き換える、ということがしたいのです。
というわけで、今回はconfig1で/etc/yum.repos.d/td.repoファイルを配置し、config2でtd-agentのインストールと設定等を行う、という二段構えのconfigをconfigSetとして用意しました。
"Metadata" : {
"AWS::CloudFormation::Init" : {
"configSets" : {
"default" : [ "config1" , "config2" ]
},
"config1" : {
"files" : {
...
}
},
"config2" : {
"packages" : {
"yum" : {
"td-agent" : []
}
},
...
}
}
}
td-agent.confの設定
td-agent.confでは、port 24224でTCPの口を開けておくと共に、自分自身の/var/log/messagesをsourceとして設定しておきます。
また、fluentdが受け付けたログデータは全て、S3に投げるようになっています。{ "Ref" : "LogBucket" }という記述によって、上で作成したS3バケット名を動的に設定するようになっています。
"/etc/td-agent/td-agent.conf" : {
"content" : { "Fn::Join" : ["", [
"<source>\n",
" type forward\n",
" port 24224\n",
"</source>\n",
"\n",
"<source>\n",
" type config_expander\n",
" <config>\n",
" type tail\n",
" format syslog\n",
" path /var/log/messages\n",
" tag ${hostname}/syslog.messages\n",
" </config>\n",
"</source>\n",
"\n",
"<match *.**>\n",
" type forest\n",
" subtype s3\n",
"\n",
" <template>\n",
" s3_bucket ", { "Ref" : "LogBucket" },"\n",
" s3_endpoint ", { "Fn::FindInMap": [ "AWSAPIEndpoint", { "Ref": "AWS::Region" }, "S3" ]}, "\n",
"\n",
" path ${tag}/\n",
" buffer_path /var/log/td-agent/buffer/${tag}\n",
"\n",
" time_slice_format %Y/%m/%d/ec2-%Y-%m-%d-%H\n",
" flush_interval 1m\n",
" </template>\n",
"</match>\n"
]]},
"mode" : "000644",
"owner" : "root",
"group" : "root"
}
また、s3_endpointにS3のエンドポイントホスト名が必要ですので、下記のようなMappingsを用意しておき、各リージョンに対応します。
"Mappings": {
...
"AWSAPIEndpoint": {
"us-east-1": { "S3": "s3.amazonaws.com" },
"us-west-2": { "S3": "s3-us-west-2.amazonaws.com" },
"us-west-1": { "S3": "s3-us-west-1.amazonaws.com" },
"eu-west-1": { "S3": "s3-eu-west-1.amazonaws.com" },
"ap-southeast-1": { "S3": "s3-ap-southeast-1.amazonaws.com" },
"ap-southeast-2": { "S3": "s3-ap-southeast-2.amazonaws.com" },
"ap-northeast-1": { "S3": "s3-ap-northeast-1.amazonaws.com" },
"sa-east-1": { "S3": "s3-sa-east-1.amazonaws.com" }
},
...
}
td-agentのインストールとfluentdの設定が終わったところで、/var/log/messagesの権限設定と、各種fluent-pluginのインストールをしておきましょう。
"commands" : {
"0-chmod" : {
"command" : "chgrp td-agent /var/log/messages && chmod g+r /var/log/messages"
},
"1-fluent-update" : {
"command" : "/usr/lib64/fluent/ruby/bin/fluent-gem update"
},
"2-fluent-plugin-s3" : {
"command" : "/usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-s3"
},
"3-fluent-plugin-forest" : {
"command" : "/usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-forest"
},
"4-fluent-plugin-config-expander" : {
"command" : "/usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-config-expander"
}
最後に、td-agentを起動します。要するにchkconfig td-agent onとservice td-agent startを行っているのが以下の記述です。
"services" : {
"sysvinit" : {
"td-agent" : { "enabled" : "true", "ensureRunning" : "true" }
}
}
動作確認
というわけで、このテンプレートでスタックを立ち上げると、自分自身の/var/log/messagesをS3バケットに上げ始めますので、しばらくすると下記のようにログがアップロードされて来ます。
ついでですので、/var/log/messagesだけではなく、fluent-catを使ってTCPのソースからもログも上げてみましょう。
$ echo '{"foo":"bar"}' | /usr/lib64/fluent/ruby/bin/fluent-cat debug.test
こちらも、しばらくすると下記のようにファイルがアップロードされて来ます。
2013-10-09T09:35:22+00:00 debug.test {"foo":"bar"}
ちゃんと来てますね!