安全に CloudWatch Logsエージェント から CloudWatch統合エージェント へ移行したい
はじめに
皆様こんにちは、あかいけです。
直近でCloudWatchエージェントを移行する機会があり、
安全に移行する方法を調べてみたので、まとめました。
CloudWatchエージェントの種類について
まずCloudWatchエージェントには以下の二種類があります。
CloudWatch Logsエージェント
CloudWatch Logsエージェント(旧エージェント)は、EC2インスタンスからCloudWatch Logsにログデータを送信するためのエージェントです。
このエージェントは単純なログ転送のみに特化しており、メトリクスの収集機能はありません。
そして公式ドキュメントにデカデカと書いてある通り、
AWSは現在このエージェントの使用を推奨していません。
なお後述のCloudWatch統合エージェントのリリースが2017年12月のため、
それ以前に構築されたEC2ではCloudWatch Logsエージェントが利用されている可能性が高いと考えられます。
CloudWatch統合エージェント
CloudWatch統合エージェント(新エージェント)は、CloudWatch Logsエージェントの後継として開発されたもので、ログ収集だけでなく、メトリクス収集、トレース収集など多機能な監視ツールです。
このエージェントはJSON形式の設定ファイルを使用し、Windows、Linux、macOSなど複数のプラットフォームに対応しています。
AWSは現在このエージェントの使用を推奨しています。
前提条件
今回は既存EC2を新規EC2へリプレースし、
合わせてCloudWatchエージェントも移行したい、という場面を想定します。
- 既存EC2(Amazon Linux2)では CloudWatch Logsエージェント を利用する
- 新規EC2(Amazon Linux2023)では CloudWatch統合エージェント を利用する
- 既存EC2(Amazon Linux2)で極力作業を行いたくない
EC2に限らず、リプレースする場合に既存環境を触れないのはよくある話で、
今回も極力既存EC2に影響を与えないで安全に移行する方法を検討します。
試験用IaC
以下は今回の検証で使ったCloudFormationです。
必要に応じてご利用ください。
CloudFormation
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template for VPC, Public Subnet, and EC2 with CloudWatch Agent and SSM Agent permissions'
Parameters:
AmazonLinuxAMI:
Description: Amazon Linux 2 AMI ID
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64'
AllowedValues:
- '/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2'
- '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64'
VpcCIDR:
Description: CIDR block for the VPC
Type: String
Default: 10.0.0.0/16
PublicSubnetCIDR:
Description: CIDR block for the public subnet
Type: String
Default: 10.0.0.0/24
Resources:
# VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-VPC
# Internet Gateway
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-IGW
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
# Public Subnet
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCIDR
MapPublicIpOnLaunch: true
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-PublicSubnet
# Route Table
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-PublicRouteTable
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
# Security Group
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable All Outbound traffic
VpcId: !Ref VPC
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-EC2SecurityGroup
# IAM Role for EC2
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
Path: /
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-EC2Role
# Instance Profile
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref EC2Role
# EC2 Instance
EC2Instance:
Type: AWS::EC2::Instance
Properties:
# InstanceType: !Ref InstanceType
InstanceType: t3.micro
SecurityGroupIds:
- !Ref EC2SecurityGroup
SubnetId: !Ref PublicSubnet
ImageId: !Ref AmazonLinuxAMI
IamInstanceProfile: !Ref EC2InstanceProfile
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-EC2Instance
Outputs:
VPC:
Description: VPC ID
Value: !Ref VPC
Export:
Name: !Sub ${AWS::StackName}-VPC
PublicSubnet:
Description: Public Subnet ID
Value: !Ref PublicSubnet
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet
EC2Instance:
Description: EC2 Instance ID
Value: !Ref EC2Instance
Export:
Name: !Sub ${AWS::StackName}-EC2Instance
EC2PublicIP:
Description: EC2 Instance Public IP
Value: !GetAtt EC2Instance.PublicIp
Export:
Name: !Sub ${AWS::StackName}-EC2PublicIP
移行手順
大まかな手順は以下の通りです。
検証用EC2でCloudWatch統合エージェントの設定ファイルを作成して、それを新規EC2で利用します。
- (1).既存EC2
- CloudWatch Logsエージェント の設定値を確認
- (2).検証用EC2
- 既存EC2の設定を元に、CloudWatch Logsエージェントを設定
- CloudWatch統合エージェントのエージェント設定ファイルウィザードで設定ファイルを作成
- (3).新規EC2
- 検証用EC2で作成した設定ファイルを利用して、CloudWatch統合エージェントをセットアップ
(1).既存EC2
まず既存のCloudWatch Logsエージェントの設定値を確認します。
以下の設定ファイルの確認しましょう。
- /etc/awslogs/awslogs.conf
- /etc/awslogs/awscli.conf
今回は以下のように、/var/log/messageなどOSログだけ収集していると仮定します。
[/var/log/messages]
datetime_format = %b %d %H:%M:%S
file = /var/log/messages
buffer_duration = 5000
log_stream_name = {instance_id}-messages
initial_position = start_of_file
log_group_name = /aws/syslog
[/var/log/audit/audit.log]
file = /var/log/audit/audit.log
buffer_duration = 5000
log_stream_name = {instance_id}-auditlog
initial_position = start_of_file
log_group_name = /aws/syslog
[/var/log/secure]
datetime_format = %b %d %H:%M:%S
file = /var/log/secure
buffer_duration = 5000
log_stream_name = {instance_id}-secure
initial_position = start_of_file
log_group_name = /aws/syslog
[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1
(2).検証用EC2
①,CloudWatch Logsエージェント セットアップ
最初に検証用のEC2インスタンスを立ち上げ、既存EC2と同じ設定でCloudWatch Logsエージェントをセットアップします。
まずはCloudWatch Logsエージェントをインストールして、
sudo yum update -y
sudo yum install -y awslogs
インストールが完了したら、既存EC2で確認した設定ファイルを作成します。
sudo vim /etc/awslogs/awslogs.conf
sudo vim /etc/awslogs/awscli.conf
CloudWatch Logsエージェントを起動します。
sudo systemctl start awslogsd
sudo systemctl enable awslogsd.service
sudo systemctl status awslogsd.service
最後にCloudWatch Logsにて正常が出力されていることを確認しましょう。
aws logs describe-log-streams \
--log-group-name '/aws/syslog'
aws logs get-log-events \
--log-group-name '/aws/syslog' \
--log-stream-name i-XXXXXXXXXXX-messages
②,CloudWatch統合エージェント 設定ファイル作成
次にCloudWatch統合エージェントの、エージェント設定ファイルウィザードで移行先の設定ファイルを作成します。
まずはCloudWatch統合エージェントをインストールして、
sudo yum -y install amazon-cloudwatch-agent
次に移行先の設定ファイルを作成します。
旧エージェントの設定を新エージェント用に変換するウィザードが用意されているので、利用しましょう。
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
ウィザードの実行中にいくつか質問されるので、
今回は以下のように回答します。
================================================================
= Welcome to the Amazon CloudWatch Agent Configuration Manager =
= =
= CloudWatch Agent allows you to collect metrics and logs from =
= your host and send them to CloudWatch. Additional CloudWatch =
= charges may apply. =
================================================================
On which OS are you planning to use the agent?
1. linux
2. windows
3. darwin
default choice: [1]:
1
Trying to fetch the default region based on ec2 metadata...
I! imds retry client will retry 1 timesAre you using EC2 or On-Premises hosts?
1. EC2
2. On-Premises
default choice: [1]:
1
Which user are you planning to run the agent?
1. cwagent
2. root
3. others
default choice: [1]:
1
Do you want to turn on StatsD daemon?
1. yes
2. no
default choice: [1]:
2
Do you want to monitor metrics from CollectD? WARNING: CollectD must be installed or the Agent will fail to start
1. yes
2. no
default choice: [1]:
2
Do you want to monitor any host metrics? e.g. CPU, memory, etc.
1. yes
2. no
default choice: [1]:
2
Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html) configuration file to import for migration?
1. yes
2. no
default choice: [2]:
1
What is the file path for the existing cloudwatch log agent configuration file?
default choice: [/var/awslogs/etc/awslogs.conf]
/etc/awslogs/awslogs.conf
Do you want to monitor any log files?
1. yes
2. no
default choice: [1]:
2
Do you want the CloudWatch agent to also retrieve X-ray traces?
1. yes
2. no
default choice: [1]:
2
Existing config JSON identified and copied to: /opt/aws/amazon-cloudwatch-agent/etc/backup-configs
Saved config file to /opt/aws/amazon-cloudwatch-agent/bin/config.json successfully.
Current config as follows:
{
"agent": {
"run_as_user": "cwagent"
},
"logs": {
"force_flush_interval": 5,
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/audit/audit.log",
"log_group_name": "/aws/syslog",
"log_stream_name": "{instance_id}-auditlog",
"retention_in_days": -1
},
{
"file_path": "/var/log/messages",
"log_group_name": "/aws/syslog",
"log_stream_name": "{instance_id}-messages",
"retention_in_days": -1,
"timestamp_format": "%b %d %H:%M:%S"
},
{
"file_path": "/var/log/secure",
"log_group_name": "/aws/syslog",
"log_stream_name": "{instance_id}-secure",
"retention_in_days": -1,
"timestamp_format": "%b %d %H:%M:%S"
}
]
}
}
}
}
Please check the above content of the config.
The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
Edit it manually if needed.
Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:
2
Program exits now.
ウィザードの実行後、以下のファイルが作成されています。
{
"agent": {
"run_as_user": "cwagent"
},
"logs": {
"force_flush_interval": 5,
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/audit/audit.log",
"log_group_name": "/aws/syslog",
"log_stream_name": "{instance_id}-auditlog",
"retention_in_days": -1
},
{
"file_path": "/var/log/messages",
"log_group_name": "/aws/syslog",
"log_stream_name": "{instance_id}-messages",
"retention_in_days": -1,
"timestamp_format": "%b %d %H:%M:%S"
},
{
"file_path": "/var/log/secure",
"log_group_name": "/aws/syslog",
"log_stream_name": "{instance_id}-secure",
"retention_in_days": -1,
"timestamp_format": "%b %d %H:%M:%S"
}
]
}
}
}
}
「retention_in_days」はロググループのログ保持期間を表しています。
注意点として、既存EC2と新規EC2のロググループと同じで、新規EC2側で別の保存期間(retention_in_days)を指定した場合、ロググループのログ保持期間は上書きされます。
なので既存設定とは異なるログ保持期間を指定したい場合は、
ロググループを分けるなどしてください。
ここまできたら、CloudWatch Logsエージェントは不要なので停止します。
sudo systemctl stop awslogsd
sudo systemctl disable awslogsd.service
sudo systemctl status awslogsd.service
次にCloudWatch統合エージェントを起動しますが、何やらエラーが出ています。
sudo systemctl start amazon-cloudwatch-agent
sudo systemctl status amazon-cloudwatch-agent
● amazon-cloudwatch-agent.service - Amazon CloudWatch Agent
Loaded: loaded (/etc/systemd/system/amazon-cloudwatch-agent.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Apr 01 06:04:28 ip-10-0-0-18.ap-northeast-1.compute.internal systemd[1]: Started Amazon CloudWatch Agent.
Apr 01 06:04:28 ip-10-0-0-18.ap-northeast-1.compute.internal start-amazon-cloudwatch-agent[3124]: D! [EC2] Found active network interface
Apr 01 06:04:28 ip-10-0-0-18.ap-northeast-1.compute.internal start-amazon-cloudwatch-agent[3124]: I! imds retry client will retry 1 timesI! Detected the instance is EC2
Apr 01 06:04:28 ip-10-0-0-18.ap-northeast-1.compute.internal start-amazon-cloudwatch-agent[3124]: 2025/04/01 06:04:28 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudw....json ...
Apr 01 06:04:28 ip-10-0-0-18.ap-northeast-1.compute.internal start-amazon-cloudwatch-agent[3124]: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json does not exist or cannot read. Skipping it.
Hint: Some lines were ellipsized, use -l to show in full.
どうやらウィザードで作成されたファイルパスと、
CloudWatch統合エージェントがデフォルトで参照するファイルパスが異なっているようなので、コピーしておきます。
sudo cp /opt/aws/amazon-cloudwatch-agent/bin/config.json /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
再度起動すると、正常にログが出力されていることが確認できるかと思います。
sudo systemctl start amazon-cloudwatch-agent
sudo systemctl enable amazon-cloudwatch-agent
sudo systemctl status amazon-cloudwatch-agent
(3).新規EC2
検証用EC2で作成した設定ファイルを利用して、新規EC2でCloudWatch統合エージェントをセットアップします。
また公式がSSM Run Command用のコマンドドキュメントを用意しているので、そちらで設定してみます。
まず以下のコマンドで、CloudWatch統合エージェントをインストールします。
aws ssm send-command \
--document-name "AWS-ConfigureAWSPackage" \
--targets "Key=instanceids,Values=i-XXXXXXXXXXX" \
--parameters '{"action":["Install"],"name":["AmazonCloudWatchAgent"]}'
次に検証用EC2で作成した設定ファイルの内容で、parameter storeを作成します。
aws ssm put-parameter \
--name "AmazonCloudWatch-Config" \
--type "String" \
--value file://cloudwatch-agent-config.json
最後にparameter storeに登録した設定ファイルを指定して、
以下のコマンドを実行します。
aws ssm send-command \
--document-name "AmazonCloudWatch-ManageAgent" \
--targets "Key=instanceids,Values=i-XXXXXXXXXXX" \
--parameters '{"action":["configure"],"mode":["ec2"],"optionalConfigurationSource":["ssm"],"optionalConfigurationLocation":["AmazonCloudWatch-Config"]}'
ここまでで新規EC2の設定は完了となります。
以下は今回の条件限定で必要となる作業なので、必要に応じて実施してください。
rsyslog インストール
Amazon Linux2023 から rsyslog がデフォルトでインストールされていないため、今回対象としている「/var/log/messages」が存在しません。
なのでインストールします。
sudo dnf install -y rsyslog
sudo systemctl start rsyslog
sudo systemctl enable rsyslog
ログファイル 読み取り権限追加
当然ですが、CloudWatch統合エージェントを実行するOSユーザーは、対象とするログファイルの読み取り権限が必要です。
今回は cwagent が実行するので、必要に応じて読み取り権限を追加します。
sudo chmod 644 /var/log/audit/audit.log
sudo chmod 644 /var/log/messages
sudo chmod 644 /var/log/secure
さいごに
今回紹介した方法では、既存EC2には手を加えず、新規EC2のみに新しいエージェントを導入することで、安全に移行を進めることができます。
ちょっと回りくどいやり方ですが、既存環境への影響はほぼ0なので、安全重視のプロジェクトで利用いただければと思います。
この記事が皆様のCloudWatchエージェント移行の一助となれば幸いです。