安全に CloudWatch Logsエージェント から CloudWatch統合エージェント へ移行したい

安全に CloudWatch Logsエージェント から CloudWatch統合エージェント へ移行したい

Clock Icon2025.04.01

はじめに

皆様こんにちは、あかいけです。

直近でCloudWatchエージェントを移行する機会があり、
安全に移行する方法を調べてみたので、まとめました。

CloudWatchエージェントの種類について

まずCloudWatchエージェントには以下の二種類があります。

CloudWatch Logsエージェント

CloudWatch Logsエージェント(旧エージェント)は、EC2インスタンスからCloudWatch Logsにログデータを送信するためのエージェントです。
このエージェントは単純なログ転送のみに特化しており、メトリクスの収集機能はありません。

そして公式ドキュメントにデカデカと書いてある通り、
AWSは現在このエージェントの使用を推奨していません。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/UsePreviousCloudWatchLogsAgent.html

なお後述のCloudWatch統合エージェントのリリースが2017年12月のため、
それ以前に構築されたEC2ではCloudWatch Logsエージェントが利用されている可能性が高いと考えられます。

https://aws.amazon.com/jp/about-aws/whats-new/2017/12/amazon-cloudwatch-introduces-a-new-cloudwatch-agent-with-aws-systems-manager-integration-for-unified-metrics-and-logs-collection/

CloudWatch統合エージェント

CloudWatch統合エージェント(新エージェント)は、CloudWatch Logsエージェントの後継として開発されたもので、ログ収集だけでなく、メトリクス収集、トレース収集など多機能な監視ツールです。

このエージェントはJSON形式の設定ファイルを使用し、Windows、Linux、macOSなど複数のプラットフォームに対応しています。
AWSは現在このエージェントの使用を推奨しています。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/UseCloudWatchUnifiedAgent.html

前提条件

今回は既存EC2を新規EC2へリプレースし、
合わせてCloudWatchエージェントも移行したい、という場面を想定します。

  • 既存EC2(Amazon Linux2)では CloudWatch Logsエージェント を利用する
  • 新規EC2(Amazon Linux2023)では CloudWatch統合エージェント を利用する
  • 既存EC2(Amazon Linux2)で極力作業を行いたくない

EC2に限らず、リプレースする場合に既存環境を触れないのはよくある話で、
今回も極力既存EC2に影響を与えないで安全に移行する方法を検討します。

試験用IaC

以下は今回の検証で使ったCloudFormationです。
必要に応じてご利用ください。

CloudFormation
ec2-cloudwatch-agent.yaml
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ログだけ収集していると仮定します。

/etc/awslogs/awslogs.conf
[/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
/etc/awslogs/awscli.conf
[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1

(2).検証用EC2

①,CloudWatch Logsエージェント セットアップ

最初に検証用のEC2インスタンスを立ち上げ、既存EC2と同じ設定でCloudWatch Logsエージェントをセットアップします。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html

まずは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

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-EC2-Instance.html

次に移行先の設定ファイルを作成します。
旧エージェントの設定を新エージェント用に変換するウィザードが用意されているので、利用しましょう。

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/create-cloudwatch-agent-configuration-file-wizard.html

ウィザードの実行中にいくつか質問されるので、
今回は以下のように回答します。

================================================================
= 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.

ウィザードの実行後、以下のファイルが作成されています。

/opt/aws/amazon-cloudwatch-agent/bin/config.json
{
        "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用のコマンドドキュメントを用意しているので、そちらで設定してみます。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/download-CloudWatch-Agent-on-EC2-Instance-SSM-first.html

まず以下のコマンドで、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」が存在しません。

https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/journald.html
https://dev.classmethod.jp/articles/amazonlinux-2023-rsyslog-install/

なのでインストールします。

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エージェント移行の一助となれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.