Fluent Bit doesn’t actually send logs to CloudWatch Logs; it just tails log files and forwards them to a designated endpoint.
Here’s how you get Fluent Bit happily tailing and forwarding logs from your application container within an ECS task definition.
# Example ECS Task Definition Snippet
Resources:
MyService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref MyCluster
TaskDefinition: !Ref MyTaskDefinition
# ... other service properties
MyTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: fluent-bit-sidecar-example
NetworkMode: awsvpc
ExecutionRoleArn: arn:aws:iam::123456789012:role/ecsTaskExecutionRole
TaskRoleArn: arn:aws:iam::123456789012:role/ecsTaskRole # For CloudWatch Logs access
Cpu: '256'
Memory: '512'
RequiresCompatibilities:
- FARGATE
ContainerDefinitions:
- Name: app-container
Image: 'public.ecr.aws/amazonlinux/amazonlinux:2023' # Replace with your app image
Command: ["sh", "-c", "echo 'Hello from app!' > /proc/1/fd/1 && sleep infinity"]
LogConfiguration: # This is where Fluent Bit will *read* from
LogDriver: awslogs
Options:
awslogs-group: /ecs/app-container # App container logs directed here for Fluent Bit to tail
awslogs-region: us-east-1
awslogs-stream-prefix: app
PortMappings:
- ContainerPort: 80
Protocol: tcp
# Mount a shared volume for Fluent Bit to access app logs
VolumesFrom:
- SourceContainer: fluent-bit-container
- Name: fluent-bit-container
Image: 'fluent/fluent-bit:latest'
Command:
- "/fluent-bit/bin/fluent-bit"
- "-c"
- "/fluent-bit/etc/fluent-bit.conf"
Essential: true # Fluent Bit is essential for logging
LogConfiguration: # Fluent Bit's own logs go here
LogDriver: awslogs
Options:
awslogs-group: /ecs/fluent-bit
awslogs-region: us-east-1
awslogs-stream-prefix: fluent-bit
# Mount the configuration file and the shared volume
Volumes:
- Host:
SourcePath: /path/to/your/fluent-bit.conf # Local path on your ECS host/Fargate ephemeral storage
ContainerPath: /fluent-bit/etc/fluent-bit.conf
MountPoints:
- SourceVolume: app-logs # This volume name matches the Volume definition below
ContainerPath: /fluent-bit/logs # Where Fluent Bit will look for logs
ReadOnly: true
Volumes:
- Name: app-logs # Define the shared volume
# For Fargate, this volume is managed by ECS and shared between containers.
# For EC2, you'd typically use host volumes.
The core idea is to have your application container write its logs to a location that the Fluent Bit container can read. In ECS, a common and effective pattern is to use a shared volume. Your application writes to a file within that shared volume, and Fluent Bit tails that file.
Here’s a simplified fluent-bit.conf that tails a file within the shared volume and forwards to CloudWatch Logs:
[SERVICE]
Flush 1
Daemon off
Log_Level info
Parsers_File parsers.conf # Optional: if you have custom parsers
[INPUT]
Name tail
Path /fluent-bit/logs/app.log # Tailing the log file in the shared volume
Tag app.log # A tag to identify these logs
Refresh_Interval 5 # Check for new log entries every 5 seconds
[OUTPUT]
Name cloudwatch_logs
Match app.log # Only process logs tagged with 'app.log'
Region us-east-1 # Your AWS region
LogGroupName /ecs/app-container # The CloudWatch Log Group name
LogStreamName_Template app-${ecs_container_name}-${ecs_task_id} # Dynamic stream naming
AutoCreateCollection true # Automatically create the log group if it doesn't exist
How it works:
- Application Container: Writes logs to a file (e.g.,
/proc/1/fd/1which is stdout/stderr, or a specific file path if configured) that is accessible via a shared volume. In the example above, we’re directing the app’s stdout/stderr to be captured by ECS’sawslogsdriver and we’re usingVolumesFromto make the app container’s log directory (where ECS writes stdout/stderr) available to Fluent Bit. If your app writes to a file, ensure that file is within the volume mounted by Fluent Bit. - Fluent Bit Container:
- Is configured to read from a specific path (
/fluent-bit/logs/app.login the example) within its own mounted volume. - Uses the
tailinput plugin to monitor this file for new entries. - The
cloudwatch_logsoutput plugin takes these entries and sends them to the specified CloudWatch Log Group and Stream.
- Is configured to read from a specific path (
- Shared Volume: The
Volumesdefinition in the task places a volume namedapp-logsinto the Fluent Bit container at/fluent-bit/logs. TheVolumesFromon theapp-containermakes the log directory of theapp-container(which is where ECS writes its stdout/stderr to be picked up by theawslogsdriver) accessible to the Fluent Bit container. This is the critical link. Fluent Bit tails the log file that the app container is writing to.
Crucial Configuration Points:
VolumesFromon App Container: This is key. It makes the log directory of theapp-container(where ECS writes stdout/stderr for log collection) accessible to thefluent-bit-container. Fluent Bit then tails the files within this directory.MountPointson Fluent Bit Container: This maps the shared volume defined at the task level (app-logs) to a specific path (/fluent-bit/logs) inside the Fluent Bit container.fluent-bit.confPath: Must point to the log file inside the Fluent Bit container, which corresponds to the shared volume mount.fluent-bit.confLogGroupNameandLogStreamName_Template: These need to match your desired CloudWatch Log Group and how you want to name your log streams. The template can use ECS metadata variables.- IAM Permissions: The
TaskRoleArnof your task definition must have permissions to write to CloudWatch Logs (logs:CreateLogGroup,logs:CreateLogStream,logs:PutLogEvents,logs:DescribeLogStreams).
This setup ensures that your application logs are first captured by Fluent Bit and then forwarded to CloudWatch Logs, giving you a robust centralized logging solution within ECS.