こんにちは、なべです。
最近レトルトカレーにはまっていて、名店のレトルトカレーの食べ比べをしています。
現在AWS環境のIaC構築を推進しており、EC2の非機能周りも自動化で実装されると嬉しいなと思いました。
関連の検索をしても非機能周りの自動実装が無かったので、私の方でログ管理のスクリプトを作成してみました。
概要
EC2起動時にユーザーデータを実行し、以下を設定します。
なお、前提としてWindowsServerであること、CloudWatchAgentをインストールするためインターネットやモジュール取得先のS3につながる環境があること、環境によっては必要なVPCエンドポイント、IAMロールが割り当てられている事が前提の条件となりますが、こちらは今回割愛します。
<CloudWatchAgent設定>
①CloudWatchAgentのインストール
②CloudWatchLogsへの出力設定(JSON)
③CloudWatchAgent起動設定
<S3イベントログアップロード設定>
①イベントログアップロードスクリプト配置
②タスクスケジューラ設定
③AWS Tools for PowerShellのインストール
概要図はこちらです
ログはいずれもSystem,Application,Securityログを送信します。
やってみましょう
今回設定するユーザーデータスクリプトはこちらです。
スクリプト内の以下6所は要件に合わせて任意で設定いただく箇所になります。
・ロググループ名
・スクリプト配置パス
・任意のプレフィックス
・任意のプレフィックス
・アップロード先S3バケット名
・タスク実行時間
# タイムゾーンを東京に設定 Set-TimeZone -Id "Tokyo Standard Time" # CloudWatch Agentのダウンロード Invoke-WebRequest -Uri "https://amazoncloudwatch-agent.s3.amazonaws.com/windows/amd64/latest/amazon-cloudwatch-agent.msi" -OutFile "amazon-cloudwatch-agent.msi" # MSIパッケージのインストール Start-Process msiexec.exe -Wait -ArgumentList "/i amazon-cloudwatch-agent.msi /qn" # # 5回までフォルダの存在を確認する # for ($i = 0; $i -lt 5; $i++) { # # フォルダの存在を確認 # if (Test-Path -Path "C:\ProgramData\Amazon\AmazonCloudWatchAgent\Configs") { # break # } else { # Start-Sleep -Seconds 5 # } # } # CloudWatch Agent設定をJSONとして保存 $configJson = @' { "agent": { "metrics_collection_interval": 60, "run_as_user": "System" }, "logs": { "logs_collected": { "windows_events": { "collect_list": [ { "event_name": "System", "event_levels": ["ERROR", "WARNING", "INFORMATION"], "log_group_name": "/nabe/tokyo/ec2/system", "log_stream_name": "{local_hostname}_{instance_id}" }, { "event_name": "Application", "event_levels": ["ERROR", "WARNING", "INFORMATION"], "log_group_name": "/nabe/tokyo/ec2/application", "log_stream_name": "{local_hostname}_{instance_id}" }, { "event_name": "Security", "event_levels": ["ERROR", "WARNING", "INFORMATION", "CRITICAL"], "log_group_name": "/nabe/tokyo/ec2/security", "log_stream_name": "{local_hostname}_{instance_id}" } ] } } }, "metrics": { "metrics_collected": { "Memory": { "measurement": [ {"name": "% Committed Bytes In Use", "unit": "Percent"} ], "metrics_collection_interval": 60 }, "LogicalDisk": { "measurement": [ {"name": "% Free Space", "unit": "Percent"} ], "metrics_collection_interval": 60, "resources": ["*"] } }, "append_dimensions": { "InstanceId": "${aws:InstanceId}", "InstanceType": "${aws:InstanceType}" } } } '@ # 設定ファイルの保存 [System.IO.File]::WriteAllText("C:\ProgramData\Amazon\AmazonCloudWatchAgent\Configs\Config.json", $configJson) # CloudWatch Agentの起動と設定 & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c file:"C:\ProgramData\Amazon\AmazonCloudWatchAgent\Configs\Config.json" Start-Sleep -Seconds 10 & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a start # エージェントのステータス確認とログ出力 & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a status | Out-File -FilePath "C:\CloudWatchAgent\agent-status.txt" # スクリプトディレクトリの作成 New-Item -ItemType Directory -Force -Path "C:\infra\script" # S3転送スクリプトの作成 $s3TransferScript = @' # 日付とホスト情報定義 $hostName = [System.Net.Dns]::GetHostName() $date = (Get-Date).AddDays(-1).ToString("yyyyMMddHHmmss") $zipFileName = "任意の名前" -f $hostName, $date # S3のバケット名とプレフィックス $bucketName = $args[0] $prefix = "任意のプレフィックス" -f $hostName # 抽出対象イベントログの名前定義 $eventLogNames = "System", "Application", "Security" # スクリプト名定義 $scriptName = $MyInvocation.MyCommand.Name # イベントソースが存在するかどうかを確認する if (-not [System.Diagnostics.EventLog]::SourceExists($scriptName)) { # イベントソースが存在しない場合、新しく作成する New-EventLog -LogName Application -Source $scriptName } # スクリプトの開始ログを出力する Write-EventLog -LogName Application -Source $scriptName -EntryType Information -EventId 100 -Message "[Info 001]: Script started." # イベントログをエクスポートしてzip化処理 ForEach ($logName in $eventLogNames) { Try { $fileName = "{0}-{1}.txt" -f $logName, $date Get-WinEvent -FilterHashtable @{ LogName=$logName; StartTime=(Get-Date).AddDays(-1).Date; EndTime=(Get-Date).Date } | Format-Table -AutoSize -Wrap > $fileName Compress-Archive -Path $fileName -Update -DestinationPath $zipFileName Remove-Item $fileName } Catch { $errorMsg = "[Error 001]: Script failed while exporting and zipping event logs. Error details: $_" Write-Error $errorMsg Write-EventLog -LogName Application -Source $scriptName -EntryType Error -EventId 1 -Message $errorMsg Break } Finally { Write-EventLog -LogName Application -Source $scriptName -EntryType Information -EventId 101 -Message "[Info 002]: Exporting and zipping event logs completed." } } # AWS S3にZIPファイルをアップロード Try { Write-S3Object -BucketName $bucketName -File $zipFileName -Key $prefix/$zipFileName } Catch { $errorMsg = "[Error 002]: Script failed while uploading the ZIP file to S3. Error details: $_" Write-Error $errorMsg Write-EventLog -LogName Application -Source $scriptName -EntryType Error -EventId 2 -Message $errorMsg } Finally { Write-EventLog -LogName Application -Source $scriptName -EntryType Information -EventId 102 -Message "[Info 003]: Uploading the ZIP file to S3 completed." Remove-Item $zipFileName } Write-Host "ZIP file has been uploaded to S3." Write-EventLog -LogName Application -Source $scriptName -EntryType Information -EventId 103 -Message "[Info 004]: Script completed." '@ # スクリプトの保存 [System.IO.File]::WriteAllText("C:\infra\script\s3_log_transfer.ps1", $s3TransferScript) # タスクスケジューラーの設定 $action = New-ScheduledTaskAction ` -Execute "PowerShell.exe" ` -Argument "-ExecutionPolicy Bypass C:\infra\script\s3_log_transfer.ps1 アップロード先S3バケット名" $trigger = New-ScheduledTaskTrigger -Daily -At 2am $settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -DontStopIfGoingOnBatteries -AllowStartIfOnBatteries Register-ScheduledTask ` -TaskName "S3EventLogTransfer" ` -Action $action ` -Trigger $trigger ` -Settings $settings ` -User "System" ` -RunLevel Highest ` -Force # AWS Tools for PowerShellのインストール Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force Install-Module -Name AWS.Tools.Common -Force Install-Module -Name AWS.Tools.S3 -Force
周辺環境のデプロイが手間なので、今回私はAWS CDKでデプロイしますが、EC2作成時にユーザーデータ欄に以下のように<powershell></powershell>と挟んでスクリプトをコピペしてください。
動作確認
まずは、CloudWatchLogsからです、SYSTEMログとSECURITYログは割愛しますが、以下のようにデプロイ直後から出力されています。
続いて、イベントログS3アップロードです。
以下のようにEC2のタスクスケジューラにタスクがしっかり登録されていました。
では、強制的に実行してみましょう。
以下のようにイベントログ(Application)に途中経過が出力されます。
S3にログがアップロードされていることを確認できました。
今回は以上となります。
少しでも皆様のお力になれれば幸いです。
次回はAWS CDK周りの案件に合わせた実装の記事を執筆したいと思います。