first claude draft
This commit is contained in:
148
infra/aws/terraform/ec2.tf
Normal file
148
infra/aws/terraform/ec2.tf
Normal file
@@ -0,0 +1,148 @@
|
||||
# EC2 Instance for Docker Compose deployment
|
||||
|
||||
resource "aws_security_group" "sysmonstm" {
|
||||
name_prefix = "${var.project_name}-"
|
||||
description = "Security group for System Monitor Platform"
|
||||
|
||||
# HTTP/HTTPS
|
||||
ingress {
|
||||
from_port = 80
|
||||
to_port = 80
|
||||
protocol = "tcp"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
description = "HTTP"
|
||||
}
|
||||
|
||||
ingress {
|
||||
from_port = 443
|
||||
to_port = 443
|
||||
protocol = "tcp"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
description = "HTTPS"
|
||||
}
|
||||
|
||||
# gRPC for collectors
|
||||
ingress {
|
||||
from_port = 50051
|
||||
to_port = 50051
|
||||
protocol = "tcp"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
description = "gRPC Aggregator"
|
||||
}
|
||||
|
||||
# SSH (restricted)
|
||||
dynamic "ingress" {
|
||||
for_each = length(var.allowed_ssh_cidrs) > 0 ? [1] : []
|
||||
content {
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = var.allowed_ssh_cidrs
|
||||
description = "SSH"
|
||||
}
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
description = "Allow all outbound"
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-sg"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "ec2" {
|
||||
name_prefix = "${var.project_name}-ec2-"
|
||||
|
||||
assume_role_policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Action = "sts:AssumeRole"
|
||||
Effect = "Allow"
|
||||
Principal = {
|
||||
Service = "ec2.amazonaws.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "ec2_ssm" {
|
||||
role = aws_iam_role.ec2.name
|
||||
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "ec2" {
|
||||
name_prefix = "${var.project_name}-"
|
||||
role = aws_iam_role.ec2.name
|
||||
}
|
||||
|
||||
resource "aws_instance" "sysmonstm" {
|
||||
ami = data.aws_ami.amazon_linux_2023.id
|
||||
instance_type = var.ec2_instance_type
|
||||
key_name = var.ec2_key_name != "" ? var.ec2_key_name : null
|
||||
vpc_security_group_ids = [aws_security_group.sysmonstm.id]
|
||||
iam_instance_profile = aws_iam_instance_profile.ec2.name
|
||||
|
||||
root_block_device {
|
||||
volume_size = 20
|
||||
volume_type = "gp3"
|
||||
encrypted = true
|
||||
}
|
||||
|
||||
user_data = <<-EOF
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Install Docker
|
||||
dnf update -y
|
||||
dnf install -y docker git
|
||||
systemctl enable docker
|
||||
systemctl start docker
|
||||
|
||||
# Install Docker Compose
|
||||
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
|
||||
-o /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# Add ec2-user to docker group
|
||||
usermod -aG docker ec2-user
|
||||
|
||||
# Clone and start the application
|
||||
cd /home/ec2-user
|
||||
git clone https://github.com/yourusername/sysmonstm.git || true
|
||||
cd sysmonstm
|
||||
|
||||
# Create .env file
|
||||
cat > .env <<EOL
|
||||
LOG_LEVEL=INFO
|
||||
MACHINE_ID=aws-demo
|
||||
EOL
|
||||
|
||||
# Start services
|
||||
docker-compose up -d
|
||||
EOF
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-server"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [ami]
|
||||
}
|
||||
}
|
||||
|
||||
# Elastic IP for stable address
|
||||
resource "aws_eip" "sysmonstm" {
|
||||
instance = aws_instance.sysmonstm.id
|
||||
domain = "vpc"
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-eip"
|
||||
}
|
||||
}
|
||||
203
infra/aws/terraform/lambda.tf
Normal file
203
infra/aws/terraform/lambda.tf
Normal file
@@ -0,0 +1,203 @@
|
||||
# Lambda Functions for Data Processing Pipeline
|
||||
# These are optional and enabled via enable_lambda_pipeline variable
|
||||
|
||||
# SQS Queue for buffering metrics
|
||||
resource "aws_sqs_queue" "metrics" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
name = "${var.project_name}-metrics"
|
||||
visibility_timeout_seconds = var.lambda_timeout * 2
|
||||
message_retention_seconds = 86400 # 24 hours
|
||||
|
||||
redrive_policy = jsonencode({
|
||||
deadLetterTargetArn = aws_sqs_queue.metrics_dlq[0].arn
|
||||
maxReceiveCount = 3
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "metrics_dlq" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
name = "${var.project_name}-metrics-dlq"
|
||||
message_retention_seconds = 1209600 # 14 days
|
||||
}
|
||||
|
||||
# S3 Bucket for metric backups
|
||||
resource "aws_s3_bucket" "metrics" {
|
||||
count = var.enable_s3_backup ? 1 : 0
|
||||
|
||||
bucket_prefix = "${var.project_name}-metrics-"
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_lifecycle_configuration" "metrics" {
|
||||
count = var.enable_s3_backup ? 1 : 0
|
||||
bucket = aws_s3_bucket.metrics[0].id
|
||||
|
||||
rule {
|
||||
id = "archive-old-metrics"
|
||||
status = "Enabled"
|
||||
|
||||
transition {
|
||||
days = 30
|
||||
storage_class = "STANDARD_IA"
|
||||
}
|
||||
|
||||
transition {
|
||||
days = 90
|
||||
storage_class = "GLACIER"
|
||||
}
|
||||
|
||||
expiration {
|
||||
days = 365
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# IAM Role for Lambda
|
||||
resource "aws_iam_role" "lambda" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
name_prefix = "${var.project_name}-lambda-"
|
||||
|
||||
assume_role_policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Action = "sts:AssumeRole"
|
||||
Effect = "Allow"
|
||||
Principal = {
|
||||
Service = "lambda.amazonaws.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "lambda" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
name = "lambda-policy"
|
||||
role = aws_iam_role.lambda[0].id
|
||||
|
||||
policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Effect = "Allow"
|
||||
Action = [
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents"
|
||||
]
|
||||
Resource = "arn:aws:logs:*:*:*"
|
||||
},
|
||||
{
|
||||
Effect = "Allow"
|
||||
Action = [
|
||||
"sqs:ReceiveMessage",
|
||||
"sqs:DeleteMessage",
|
||||
"sqs:GetQueueAttributes"
|
||||
]
|
||||
Resource = aws_sqs_queue.metrics[0].arn
|
||||
},
|
||||
{
|
||||
Effect = "Allow"
|
||||
Action = [
|
||||
"s3:PutObject",
|
||||
"s3:GetObject"
|
||||
]
|
||||
Resource = var.enable_s3_backup ? "${aws_s3_bucket.metrics[0].arn}/*" : "*"
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
# Lambda function for metric aggregation
|
||||
resource "aws_lambda_function" "aggregator" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
function_name = "${var.project_name}-aggregator"
|
||||
role = aws_iam_role.lambda[0].arn
|
||||
handler = "main.handler"
|
||||
runtime = "python3.11"
|
||||
timeout = var.lambda_timeout
|
||||
memory_size = var.lambda_memory_size
|
||||
|
||||
# Placeholder - will be deployed via CI/CD
|
||||
filename = "${path.module}/../lambdas/aggregator/placeholder.zip"
|
||||
source_code_hash = filebase64sha256("${path.module}/../lambdas/aggregator/placeholder.zip")
|
||||
|
||||
environment {
|
||||
variables = {
|
||||
TIMESCALE_HOST = aws_instance.sysmonstm.private_ip
|
||||
LOG_LEVEL = "INFO"
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [filename, source_code_hash]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_lambda_event_source_mapping" "sqs_trigger" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
event_source_arn = aws_sqs_queue.metrics[0].arn
|
||||
function_name = aws_lambda_function.aggregator[0].arn
|
||||
batch_size = 100
|
||||
|
||||
scaling_config {
|
||||
maximum_concurrency = 5
|
||||
}
|
||||
}
|
||||
|
||||
# CloudWatch Event for scheduled compaction
|
||||
resource "aws_cloudwatch_event_rule" "compactor" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
name = "${var.project_name}-compactor-schedule"
|
||||
description = "Trigger metric compaction every hour"
|
||||
schedule_expression = "rate(1 hour)"
|
||||
}
|
||||
|
||||
resource "aws_lambda_function" "compactor" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
function_name = "${var.project_name}-compactor"
|
||||
role = aws_iam_role.lambda[0].arn
|
||||
handler = "main.handler"
|
||||
runtime = "python3.11"
|
||||
timeout = 300
|
||||
memory_size = 512
|
||||
|
||||
filename = "${path.module}/../lambdas/compactor/placeholder.zip"
|
||||
source_code_hash = filebase64sha256("${path.module}/../lambdas/compactor/placeholder.zip")
|
||||
|
||||
environment {
|
||||
variables = {
|
||||
TIMESCALE_HOST = aws_instance.sysmonstm.private_ip
|
||||
S3_BUCKET = var.enable_s3_backup ? aws_s3_bucket.metrics[0].bucket : ""
|
||||
LOG_LEVEL = "INFO"
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [filename, source_code_hash]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "compactor" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
rule = aws_cloudwatch_event_rule.compactor[0].name
|
||||
target_id = "compactor-lambda"
|
||||
arn = aws_lambda_function.compactor[0].arn
|
||||
}
|
||||
|
||||
resource "aws_lambda_permission" "compactor_cloudwatch" {
|
||||
count = var.enable_lambda_pipeline ? 1 : 0
|
||||
|
||||
statement_id = "AllowCloudWatchInvoke"
|
||||
action = "lambda:InvokeFunction"
|
||||
function_name = aws_lambda_function.compactor[0].function_name
|
||||
principal = "events.amazonaws.com"
|
||||
source_arn = aws_cloudwatch_event_rule.compactor[0].arn
|
||||
}
|
||||
58
infra/aws/terraform/main.tf
Normal file
58
infra/aws/terraform/main.tf
Normal file
@@ -0,0 +1,58 @@
|
||||
# System Monitor Platform - AWS Infrastructure
|
||||
#
|
||||
# This Terraform configuration sets up:
|
||||
# - EC2 instance for running Docker Compose (demo/staging)
|
||||
# - Lambda functions for data processing pipeline
|
||||
# - SQS queue for buffering metrics
|
||||
# - S3 bucket for metric backups
|
||||
# - Security groups and IAM roles
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
}
|
||||
|
||||
# Uncomment for remote state
|
||||
# backend "s3" {
|
||||
# bucket = "your-terraform-state-bucket"
|
||||
# key = "sysmonstm/terraform.tfstate"
|
||||
# region = "us-east-1"
|
||||
# }
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = var.aws_region
|
||||
|
||||
default_tags {
|
||||
tags = {
|
||||
Project = "sysmonstm"
|
||||
Environment = var.environment
|
||||
ManagedBy = "terraform"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Data sources
|
||||
data "aws_availability_zones" "available" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
data "aws_ami" "amazon_linux_2023" {
|
||||
most_recent = true
|
||||
owners = ["amazon"]
|
||||
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["al2023-ami-*-x86_64"]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "virtualization-type"
|
||||
values = ["hvm"]
|
||||
}
|
||||
}
|
||||
36
infra/aws/terraform/outputs.tf
Normal file
36
infra/aws/terraform/outputs.tf
Normal file
@@ -0,0 +1,36 @@
|
||||
# Outputs
|
||||
|
||||
output "ec2_public_ip" {
|
||||
description = "Public IP of the EC2 instance"
|
||||
value = aws_eip.sysmonstm.public_ip
|
||||
}
|
||||
|
||||
output "ec2_instance_id" {
|
||||
description = "EC2 instance ID"
|
||||
value = aws_instance.sysmonstm.id
|
||||
}
|
||||
|
||||
output "dashboard_url" {
|
||||
description = "URL for the monitoring dashboard"
|
||||
value = "http://${aws_eip.sysmonstm.public_ip}:8000"
|
||||
}
|
||||
|
||||
output "grpc_endpoint" {
|
||||
description = "gRPC endpoint for collectors"
|
||||
value = "${aws_eip.sysmonstm.public_ip}:50051"
|
||||
}
|
||||
|
||||
output "sqs_queue_url" {
|
||||
description = "SQS queue URL for metrics"
|
||||
value = var.enable_lambda_pipeline ? aws_sqs_queue.metrics[0].url : null
|
||||
}
|
||||
|
||||
output "s3_bucket" {
|
||||
description = "S3 bucket for metric backups"
|
||||
value = var.enable_s3_backup ? aws_s3_bucket.metrics[0].bucket : null
|
||||
}
|
||||
|
||||
output "ssh_command" {
|
||||
description = "SSH command to connect to the instance"
|
||||
value = var.ec2_key_name != "" ? "ssh -i ${var.ec2_key_name}.pem ec2-user@${aws_eip.sysmonstm.public_ip}" : "Use SSM Session Manager"
|
||||
}
|
||||
16
infra/aws/terraform/terraform.tfvars.example
Normal file
16
infra/aws/terraform/terraform.tfvars.example
Normal file
@@ -0,0 +1,16 @@
|
||||
# Example Terraform variables
|
||||
# Copy to terraform.tfvars and fill in your values
|
||||
|
||||
aws_region = "us-east-1"
|
||||
environment = "staging"
|
||||
project_name = "sysmonstm"
|
||||
domain_name = "sysmonstm.mcrn.ar"
|
||||
|
||||
# EC2
|
||||
ec2_instance_type = "t2.small"
|
||||
ec2_key_name = "your-key-pair-name"
|
||||
allowed_ssh_cidrs = ["YOUR.IP.ADDRESS/32"]
|
||||
|
||||
# Feature flags
|
||||
enable_lambda_pipeline = false
|
||||
enable_s3_backup = false
|
||||
70
infra/aws/terraform/variables.tf
Normal file
70
infra/aws/terraform/variables.tf
Normal file
@@ -0,0 +1,70 @@
|
||||
# Variables for System Monitor Platform
|
||||
|
||||
variable "aws_region" {
|
||||
description = "AWS region to deploy to"
|
||||
type = string
|
||||
default = "us-east-1"
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
description = "Environment name (dev, staging, prod)"
|
||||
type = string
|
||||
default = "staging"
|
||||
}
|
||||
|
||||
variable "project_name" {
|
||||
description = "Project name for resource naming"
|
||||
type = string
|
||||
default = "sysmonstm"
|
||||
}
|
||||
|
||||
variable "domain_name" {
|
||||
description = "Domain name for the service"
|
||||
type = string
|
||||
default = "sysmonstm.mcrn.ar"
|
||||
}
|
||||
|
||||
# EC2 Configuration
|
||||
variable "ec2_instance_type" {
|
||||
description = "EC2 instance type"
|
||||
type = string
|
||||
default = "t2.small"
|
||||
}
|
||||
|
||||
variable "ec2_key_name" {
|
||||
description = "SSH key pair name"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "allowed_ssh_cidrs" {
|
||||
description = "CIDR blocks allowed to SSH"
|
||||
type = list(string)
|
||||
default = [] # Set to your IP for security
|
||||
}
|
||||
|
||||
# Lambda Configuration
|
||||
variable "lambda_memory_size" {
|
||||
description = "Lambda function memory in MB"
|
||||
type = number
|
||||
default = 256
|
||||
}
|
||||
|
||||
variable "lambda_timeout" {
|
||||
description = "Lambda function timeout in seconds"
|
||||
type = number
|
||||
default = 60
|
||||
}
|
||||
|
||||
# Feature flags
|
||||
variable "enable_lambda_pipeline" {
|
||||
description = "Enable Lambda data processing pipeline"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "enable_s3_backup" {
|
||||
description = "Enable S3 backup for metrics"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
Reference in New Issue
Block a user