🐦

Jornald を Fluent-bit で CW Logs へ in Amazon Linux 2022

2022/10/01に公開

初めに

AmazonLinux2022(AL2022)でsyslogをCloudwatch logsに連携するの難しいよね、という話があった。

具体的な問題を下に挙げる。

  • AL2022はFedoraベースで、ログ保存管理のデフォルトがsystemd-journald (以下 journald)扱い。
  • rsyslogはデフォルトで入っていない。
  • CloudWatch Agentでsyslogを持ってくる例は「/var/log/messages」「/var/log/syslog」ばかり。Journalの例は見つからない。

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

で、journald → Fluent bit → CW Logsができるといいよね。と思ったら良さそうなサンプルがなかったのでメモ。

ステップ

  1. AL2022環境をCDKで作成する
  2. Fluent Bitを設定
  3. 実践

Step1 AL2022環境をCDKで作成する

前提として、以降の環境は「us-east-1」リージョンで実施している。

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as iam from "aws-cdk-lib/aws-iam";
import * as logs from "aws-cdk-lib/aws-logs";

export class FluentdTestStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, "sample-nw", {
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "public-1",
          subnetType: ec2.SubnetType.PUBLIC,
        },
      ],
      maxAzs: 1,
    });
    
    // loggroup for fluent bit
    new logs.LogGroup(this, 'fluentLogGroup', {
      logGroupName: "fluent-bit-test",
      removalPolicy: cdk.RemovalPolicy.DESTROY
    });
    
    const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", {
      vpc: vpc,
      allowAllOutbound: true,
    });
    const role = new iam.Role(this, "ec2-role", {
      assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "AmazonSSMManagedInstanceCore"
        ),
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "CloudWatchAgentAdminPolicy"
        ),
      ],
      roleName: `cdk-test-ec2-role`,
    });
    // AWS Linux
    const al2022Vm = new ec2.Instance(this, "Instance1", {
      vpc,
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T3,
        ec2.InstanceSize.MICRO
      ),
      // Amazon linux 2022への参照が壊れている
      // machineImage: new ec2.AmazonLinuxImage({
      //   generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2022,
      //   cpuType: ec2.AmazonLinuxCpuType.X86_64,
      // }),
      machineImage: ec2.MachineImage.fromSsmParameter(
        "/aws/service/ami-amazon-linux-latest/al2022-ami-kernel-default-x86_64"
      ),
      securityGroup,
      role,
    });
    al2022Vm.userData.addCommands(
      "cd /tmp",
      "sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm",
      "sudo systemctl enable amazon-ssm-agent",
      "sudo systemctl start amazon-ssm-agent",
      "sudo dnf install -y amazon-cloudwatch-agent",
      "sudo systemctl enable amazon-cloudwatch-agent",
      "sudo systemctl start amazon-cloudwatch-agent",
      "sudo dnf install -y docker",
      "sudo systemctl enable docker",
      "sudo systemctl start docker",
      "sudo usermod -a -G docker ec2-user",
      "sudo su - ec2-user",
      "sudo mkdir -p /var/log/journal",
    );
  }
}

Tips

  • AMIはコメントアウトした部分の書き方が正しいが、バグにより現在は使えない。
  • userdataの意図
    • SSM-Agent, CW-Agentをインストールしサービス登録
      • よく考えると後者は不要でした。
    • Dockerをインストール、サービス登録、ユーザ(ec2-user)でも実行可能な設定に
    • /var/log/journalフォルダを作成。
  • /var/log/journalを作る理由はログ永続化のため。
    • デフォルト設定は「/var/log/journal」。なければ「/run/log/journal」にログを保管。
    • 念のためですが、「/run/log/journal」は揮発性。

2. Fluent Bitを設定する

Config

fluent-bit.conf
[SERVICE]
    Flush        1
    Daemon       Off
    Log_Level    info
[INPUT]
    Name            systemd
    Tag             *
    Path            /var/log/journal
#   Systemd_Filter    _SYSTEMD_UNIT=docker.service
[OUTPUT]
    Name cloudwatch_logs
    Match   *
    region us-east-1
    log_group_name fluent-bit-test
    log_stream_prefix i-xxxxxxxxxx_

Tips

もう少しチューニングしたい場合はここが参考になりそう。

https://docs.fluentbit.io/manual/pipeline/inputs/systemd
https://docs.fluentbit.io/manual/pipeline/outputs/cloudwatch

Docker

fluent bitを起動するcompose設定です。

docker-compose.yml
version: "3.7"

services:
  fluent-bit:
      image: 'bitnami/fluent-bit:latest'
      restart: always
      user: root
      network_mode: host
      command: -c /fluent-bit/etc/fluent-bit.conf
      volumes:
        - ./fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
        - /etc/machine-id:/etc/machine-id:ro
        - /var/log/journal:/var/log/journal

Tips

Stack Overflowのこのスレッドの回答の引用だが、以下がポイント。

https://stackoverflow.com/questions/64333292/how-to-access-logs-logged-in-journald-using-fluent-bit-thats-inside-a-docker-co

  • Journaldへのアクセスには root 権限が必要なため、fluent bit コンテナの root実行が必要。
  • docker のマシン ID をhostと同じに設定します。

3. 実践

Session Managerからサーバへ入り、作業用ユーザに切り替える

sudo su - ec2-user

※Dockerのversionがxxxxなのに、AL2022のDockerはなぜかComposeが使えないのでプラグインを導入する

DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose

2.で作成したファイルを配置し、Fluent-bitを起動する。

docker compose up -d 
sudo systemctl restart amazon-ssm-agent

これで無事にamazon-ssm-agentのログがCW Logsに連携できている。
※ちょっとログが多すぎるときは、.confのコメントアウトを参考にフィルタした方が使いやすそう。

おまけ

ちなみに前提にこう書いたのだけど、この検証をした時はそもそも利用できないと勘違いしていた。

  • rsyslogはデフォルトで入っていない。

実際は導入できる。

sudo yum list rsyslog
Last metadata expiration check: 0:15:28 ago on Fri 30 Sep 2022 02:58:17 PM UTC.
Installed Packages
rsyslog.x86_64                                                                                8.2204.0-1.amzn2022.0.3                                                                                 @amazonlinux

まあFluent bitの勉強代ということで。この辺読んで勉強しよう。

https://gihyo.jp/book/2022/978-4-297-13109-8

Discussion