# 3.1.1 Terraform backend için S3 bucket ve DynamoDB table oluştur
cd ~/devops-infrastructure/terraform
# 3.1.2 Backend setup script
cat > setup-backend.sh << 'EOF'
#!/bin/bash
# Variables
BUCKET_NAME="devops-terraform-state-$(openssl rand -hex 8)"
REGION="eu-west-1"
DYNAMODB_TABLE="terraform-state-lock"
# S3 bucket oluştur
aws s3 mb s3://$BUCKET_NAME --region $REGION
# S3 bucket versioning aktifleştir
aws s3api put-bucket-versioning \
--bucket $BUCKET_NAME \
--versioning-configuration Status=Enabled
# S3 bucket encryption aktifleştir
aws s3api put-bucket-encryption \
--bucket $BUCKET_NAME \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
}'
# DynamoDB table oluştur
aws dynamodb create-table \
--table-name $DYNAMODB_TABLE \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--region $REGION
echo "Backend setup completed!"
echo "S3 Bucket: $BUCKET_NAME"
echo "DynamoDB Table: $DYNAMODB_TABLE"
echo "Region: $REGION"
# .env dosyasına kaydet
cat > ../.env << EOF
export TF_VAR_backend_bucket=$BUCKET_NAME
export TF_VAR_backend_region=$REGION
export TF_VAR_backend_dynamodb_table=$DYNAMODB_TABLE
EOF
EOF
chmod +x setup-backend.sh
./setup-backend.sh
source ../.env
# 3.2.1 Terraform modules dizin yapısı
cd ~/devops-infrastructure/terraform/modules
# 3.2.2 VPC module
mkdir -p vpc
cat > vpc/main.tf << 'EOF'
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
variable "availability_zones" {
description = "Availability zones"
type = list(string)
default = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
}
variable "environment" {
description = "Environment name"
type = string
}
variable "project_name" {
description = "Project name"
type = string
}
# VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-${var.environment}-vpc"
Environment = var.environment
Project = var.project_name
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-${var.environment}-igw"
Environment = var.environment
Project = var.project_name
}
}
# Public Subnets
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-${var.environment}-public-${count.index + 1}"
Environment = var.environment
Project = var.project_name
Type = "public"
}
}
# Private Subnets
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + length(var.availability_zones))
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.project_name}-${var.environment}-private-${count.index + 1}"
Environment = var.environment
Project = var.project_name
Type = "private"
}
}
# Elastic IPs for NAT Gateways
resource "aws_eip" "nat" {
count = length(var.availability_zones)
domain = "vpc"
depends_on = [aws_internet_gateway.main]
tags = {
Name = "${var.project_name}-${var.environment}-eip-${count.index + 1}"
Environment = var.environment
Project = var.project_name
}
}
# NAT Gateways
resource "aws_nat_gateway" "main" {
count = length(var.availability_zones)
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = {
Name = "${var.project_name}-${var.environment}-nat-${count.index + 1}"
Environment = var.environment
Project = var.project_name
}
depends_on = [aws_internet_gateway.main]
}
# Route table for public subnets
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.project_name}-${var.environment}-public-rt"
Environment = var.environment
Project = var.project_name
}
}
# Route table associations for public subnets
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# Route tables for private subnets
resource "aws_route_table" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main[count.index].id
}
tags = {
Name = "${var.project_name}-${var.environment}-private-rt-${count.index + 1}"
Environment = var.environment
Project = var.project_name
}
}
# Route table associations for private subnets
resource "aws_route_table_association" "private" {
count = length(aws_subnet.private)
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private[count.index].id
}
# VPC Flow Logs
resource "aws_flow_log" "vpc" {
iam_role_arn = aws_iam_role.flow_log.arn
log_destination = aws_cloudwatch_log_group.vpc_flow_log.arn
traffic_type = "ALL"
vpc_id = aws_vpc.main.id
}
resource "aws_cloudwatch_log_group" "vpc_flow_log" {
name = "/aws/vpc/flow-logs"
retention_in_days = 7
}
resource "aws_iam_role" "flow_log" {
name = "${var.project_name}-${var.environment}-flow-log-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy" "flow_log" {
name = "${var.project_name}-${var.environment}-flow-log-policy"
role = aws_iam_role.flow_log.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Effect = "Allow"
Resource = "*"
}
]
})
}
EOF
cat > vpc/outputs.tf << 'EOF'
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "vpc_cidr_block" {
description = "CIDR block of the VPC"
value = aws_vpc.main.cidr_block
}
output "public_subnet_ids" {
description = "IDs of the public subnets"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "IDs of the private subnets"
value = aws_subnet.private[*].id
}
output "internet_gateway_id" {
description = "ID of the Internet Gateway"
value = aws_internet_gateway.main.id
}
output "nat_gateway_ids" {
description = "IDs of the NAT Gateways"
value = aws_nat_gateway.main[*].id
}
EOF
cat > vpc/versions.tf << 'EOF'
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
EOF
🔒 3.3 Security Groups Module
# 3.3.1 Security Groups module
mkdir -p security-groups
cat > security-groups/main.tf << 'EOF'
variable "vpc_id" {
description = "VPC ID"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "project_name" {
description = "Project name"
type = string
}
# ALB Security Group
resource "aws_security_group" "alb" {
name_prefix = "${var.project_name}-${var.environment}-alb-"
vpc_id = var.vpc_id
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-alb-sg"
Environment = var.environment
Project = var.project_name
}
lifecycle {
create_before_destroy = true
}
}
# EKS Cluster Security Group
resource "aws_security_group" "eks_cluster" {
name_prefix = "${var.project_name}-${var.environment}-eks-cluster-"
vpc_id = var.vpc_id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-eks-cluster-sg"
Environment = var.environment
Project = var.project_name
}
lifecycle {
create_before_destroy = true
}
}
# EKS Node Group Security Group
resource "aws_security_group" "eks_nodes" {
name_prefix = "${var.project_name}-${var.environment}-eks-nodes-"
vpc_id = var.vpc_id
ingress {
description = "Allow nodes to communicate with each other"
from_port = 0
to_port = 65535
protocol = "tcp"
self = true
}
ingress {
description = "Allow worker Kubelets and pods to receive communication from the cluster control plane"
from_port = 1025
to_port = 65535
protocol = "tcp"
security_groups = [aws_security_group.eks_cluster.id]
}
ingress {
description = "Allow pods running extension API servers on port 443 to receive communication from cluster control plane"
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = [aws_security_group.eks_cluster.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-eks-nodes-sg"
Environment = var.environment
Project = var.project_name
}
lifecycle {
create_before_destroy = true
}
}
# RDS Security Group
resource "aws_security_group" "rds" {
name_prefix = "${var.project_name}-${var.environment}-rds-"
vpc_id = var.vpc_id
ingress {
description = "MySQL/Aurora"
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [aws_security_group.eks_nodes.id]
}
ingress {
description = "PostgreSQL"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.eks_nodes.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-rds-sg"
Environment = var.environment
Project = var.project_name
}
lifecycle {
create_before_destroy = true
}
}
# ElastiCache Security Group
resource "aws_security_group" "elasticache" {
name_prefix = "${var.project_name}-${var.environment}-elasticache-"
vpc_id = var.vpc_id
ingress {
description = "Redis"
from_port = 6379
to_port = 6379
protocol = "tcp"
security_groups = [aws_security_group.eks_nodes.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-elasticache-sg"
Environment = var.environment
Project = var.project_name
}
lifecycle {
create_before_destroy = true
}
}
EOF
cat > security-groups/outputs.tf << 'EOF'
output "alb_security_group_id" {
description = "ALB Security Group ID"
value = aws_security_group.alb.id
}
output "eks_cluster_security_group_id" {
description = "EKS Cluster Security Group ID"
value = aws_security_group.eks_cluster.id
}
output "eks_nodes_security_group_id" {
description = "EKS Nodes Security Group ID"
value = aws_security_group.eks_nodes.id
}
output "rds_security_group_id" {
description = "RDS Security Group ID"
value = aws_security_group.rds.id
}
output "elasticache_security_group_id" {
description = "ElastiCache Security Group ID"
value = aws_security_group.elasticache.id
}
EOF
🔧 3.4 EKS Module
# 3.4.1 EKS module
mkdir -p eks
cat > eks/main.tf << 'EOF'
variable "cluster_name" {
description = "EKS cluster name"
type = string
}
variable "cluster_version" {
description = "Kubernetes version"
type = string
default = "1.30"
}
variable "subnet_ids" {
description = "Subnet IDs for EKS cluster"
type = list(string)
}
variable "node_subnet_ids" {
description = "Subnet IDs for EKS node groups"
type = list(string)
}
variable "cluster_security_group_id" {
description = "Security group ID for EKS cluster"
type = string
}
variable "node_security_group_id" {
description = "Security group ID for EKS nodes"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "project_name" {
description = "Project name"
type = string
}
# EKS Cluster IAM Role
resource "aws_iam_role" "cluster" {
name = "${var.project_name}-${var.environment}-eks-cluster-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "eks.amazonaws.com"
}
}
]
})
tags = {
Environment = var.environment
Project = var.project_name
}
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = aws_iam_role.cluster.name
}
# EKS Node Group IAM Role
resource "aws_iam_role" "node_group" {
name = "${var.project_name}-${var.environment}-eks-node-group-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})
tags = {
Environment = var.environment
Project = var.project_name
}
}
resource "aws_iam_role_policy_attachment" "node_group_AmazonEKSWorkerNodePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
role = aws_iam_role.node_group.name
}
resource "aws_iam_role_policy_attachment" "node_group_AmazonEKS_CNI_Policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = aws_iam_role.node_group.name
}
resource "aws_iam_role_policy_attachment" "node_group_AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = aws_iam_role.node_group.name
}
# EKS Cluster
resource "aws_eks_cluster" "main" {
name = var.cluster_name
role_arn = aws_iam_role.cluster.arn
version = var.cluster_version
vpc_config {
subnet_ids = var.subnet_ids
security_group_ids = [var.cluster_security_group_id]
endpoint_private_access = true
endpoint_public_access = true
public_access_cidrs = ["0.0.0.0/0"]
}
enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
encryption_config {
provider {
key_arn = aws_kms_key.eks.arn
}
resources = ["secrets"]
}
depends_on = [
aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy,
aws_cloudwatch_log_group.eks
]
tags = {
Name = var.cluster_name
Environment = var.environment
Project = var.project_name
}
}
# CloudWatch Log Group for EKS
resource "aws_cloudwatch_log_group" "eks" {
name = "/aws/eks/${var.cluster_name}/cluster"
retention_in_days = 7
}
# KMS Key for EKS encryption
resource "aws_kms_key" "eks" {
description = "EKS Secret Encryption Key"
deletion_window_in_days = 7
tags = {
Name = "${var.project_name}-${var.environment}-eks-kms"
Environment = var.environment
Project = var.project_name
}
}
resource "aws_kms_alias" "eks" {
name = "alias/${var.project_name}-${var.environment}-eks"
target_key_id = aws_kms_key.eks.key_id
}
# EKS Node Group
resource "aws_eks_node_group" "main" {
cluster_name = aws_eks_cluster.main.name
node_group_name = "${var.cluster_name}-node-group"
node_role_arn = aws_iam_role.node_group.arn
subnet_ids = var.node_subnet_ids
capacity_type = "ON_DEMAND"
ami_type = "AL2_x86_64"
instance_types = ["t3.medium"]
disk_size = 20
scaling_config {
desired_size = 2
max_size = 10
min_size = 1
}
update_config {
max_unavailable = 1
}
# Remote access configuration
remote_access {
ec2_ssh_key = aws_key_pair.eks_nodes.key_name
source_security_group_ids = [var.node_security_group_id]
}
depends_on = [
aws_iam_role_policy_attachment.node_group_AmazonEKSWorkerNodePolicy,
aws_iam_role_policy_attachment.node_group_AmazonEKS_CNI_Policy,
aws_iam_role_policy_attachment.node_group_AmazonEC2ContainerRegistryReadOnly,
]
tags = {
Name = "${var.cluster_name}-node-group"
Environment = var.environment
Project = var.project_name
}
}
# SSH Key Pair for EKS nodes
resource "aws_key_pair" "eks_nodes" {
key_name = "${var.cluster_name}-eks-nodes"
public_key = file("~/.ssh/id_rsa.pub")
tags = {
Name = "${var.cluster_name}-eks-nodes"
Environment = var.environment
Project = var.project_name
}
}
# EKS Add-ons
resource "aws_eks_addon" "coredns" {
cluster_name = aws_eks_cluster.main.name
addon_name = "coredns"
addon_version = "v1.10.1-eksbuild.5"
resolve_conflicts_on_create = "OVERWRITE"
}
resource "aws_eks_addon" "kube_proxy" {
cluster_name = aws_eks_cluster.main.name
addon_name = "kube-proxy"
addon_version = "v1.30.0-eksbuild.1" # 'aws eks describe-addon-versions' ile cluster sürümüne uygun olanı seç
resolve_conflicts_on_create = "OVERWRITE"
}
resource "aws_eks_addon" "vpc_cni" {
cluster_name = aws_eks_cluster.main.name
addon_name = "vpc-cni"
addon_version = "v1.15.1-eksbuild.1"
resolve_conflicts_on_create = "OVERWRITE"
}
resource "aws_eks_addon" "ebs_csi" {
cluster_name = aws_eks_cluster.main.name
addon_name = "aws-ebs-csi-driver"
addon_version = "v1.25.0-eksbuild.1"
resolve_conflicts_on_create = "OVERWRITE"
}
EOF
cat > eks/outputs.tf << 'EOF'
output "cluster_id" {
description = "EKS cluster ID"
value = aws_eks_cluster.main.id
}
output "cluster_arn" {
description = "EKS cluster ARN"
value = aws_eks_cluster.main.arn
}
output "cluster_endpoint" {
description = "EKS cluster endpoint"
value = aws_eks_cluster.main.endpoint
}
output "cluster_security_group_id" {
description = "EKS cluster security group ID"
value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
}
output "cluster_certificate_authority_data" {
description = "EKS cluster certificate authority data"
value = aws_eks_cluster.main.certificate_authority[0].data
}
output "cluster_version" {
description = "EKS cluster Kubernetes version"
value = aws_eks_cluster.main.version
}
output "node_group_arn" {
description = "EKS node group ARN"
value = aws_eks_node_group.main.arn
}
output "node_group_status" {
description = "EKS node group status"
value = aws_eks_node_group.main.status
}
EOF
🗃️ 3.5 RDS Module
# 3.5.1 RDS module
mkdir -p rds
cat > rds/main.tf << 'EOF'
variable "db_name" {
description = "Database name"
type = string
}
variable "db_username" {
description = "Database username"
type = string
default = "admin"
}
variable "db_password" {
description = "Database password"
type = string
sensitive = true
}
variable "subnet_ids" {
description = "Subnet IDs for RDS"
type = list(string)
}
variable "security_group_id" {
description = "Security group ID for RDS"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "project_name" {
description = "Project name"
type = string
}
variable "engine" {
description = "Database engine"
type = string
default = "postgres"
}
variable "engine_version" {
description = "Database engine version"
type = string
default = "15.4"
}
variable "instance_class" {
description = "RDS instance class"
type = string
default = "db.t3.micro"
}
variable "allocated_storage" {
description = "RDS allocated storage"
type = number
default = 20
}
variable "backup_retention_period" {
description = "Backup retention period in days"
type = number
default = 7
}
# DB Subnet Group
resource "aws_db_subnet_group" "main" {
name = "${var.project_name}-${var.environment}-db-subnet-group"
subnet_ids = var.subnet_ids
tags = {
Name = "${var.project_name}-${var.environment}-db-subnet-group"
Environment = var.environment
Project = var.project_name
}
}
# DB Parameter Group
resource "aws_db_parameter_group" "main" {
family = "${var.engine}15"
name = "${var.project_name}-${var.environment}-db-params"
dynamic "parameter" {
for_each = var.engine == "postgres" ? [
{
name = "log_statement"
value = "all"
},
{
name = "log_duration"
value = "1"
},
{
name = "log_min_duration_statement"
value = "1000"
}
] : []
content {
name = parameter.value.name
value = parameter.value.value
}
}
tags = {
Name = "${var.project_name}-${var.environment}-db-params"
Environment = var.environment
Project = var.project_name
}
}
# KMS Key for RDS encryption
resource "aws_kms_key" "rds" {
description = "RDS encryption key"
deletion_window_in_days = 7
tags = {
Name = "${var.project_name}-${var.environment}-rds-kms"
Environment = var.environment
Project = var.project_name
}
}
resource "aws_kms_alias" "rds" {
name = "alias/${var.project_name}-${var.environment}-rds"
target_key_id = aws_kms_key.rds.key_id
}
# RDS Instance
resource "aws_db_instance" "main" {
identifier = "${var.project_name}-${var.environment}-db"
# Engine options
engine = var.engine
engine_version = var.engine_version
instance_class = var.instance_class
# Storage
allocated_storage = var.allocated_storage
max_allocated_storage = var.allocated_storage * 2
storage_type = "gp3"
storage_encrypted = true
kms_key_id = aws_kms_key.rds.arn
# Database
db_name = var.db_name
username = var.db_username
password = var.db_password
# Network & Security
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [var.security_group_id]
publicly_accessible = false
# Backup
backup_retention_period = var.backup_retention_period
backup_window = "03:00-04:00"
maintenance_window = "sun:04:00-sun:05:00"
# Monitoring
monitoring_interval = 60
monitoring_role_arn = aws_iam_role.rds_monitoring.arn
# Performance Insights
performance_insights_enabled = true
performance_insights_kms_key_id = aws_kms_key.rds.arn
# Parameters
parameter_group_name = aws_db_parameter_group.main.name
# Deletion protection
deletion_protection = var.environment == "prod" ? true : false
skip_final_snapshot = var.environment == "prod" ? false : true
final_snapshot_identifier = var.environment == "prod" ? "${var.project_name}-${var.environment}-final-snapshot-${formatdate("YYYY-MM-DD-hhmm", timestamp())}" : null
tags = {
Name = "${var.project_name}-${var.environment}-db"
Environment = var.environment
Project = var.project_name
}
}
# IAM Role for RDS Enhanced Monitoring
resource "aws_iam_role" "rds_monitoring" {
name = "${var.project_name}-${var.environment}-rds-monitoring-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "monitoring.rds.amazonaws.com"
}
}
]
})
tags = {
Environment = var.environment
Project = var.project_name
}
}
resource "aws_iam_role_policy_attachment" "rds_monitoring" {
role = aws_iam_role.rds_monitoring.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
# Read Replica (for production)
resource "aws_db_instance" "read_replica" {
count = var.environment == "prod" ? 1 : 0
identifier = "${var.project_name}-${var.environment}-db-read-replica"
replicate_source_db = aws_db_instance.main.identifier
instance_class = var.instance_class
# Network & Security
vpc_security_group_ids = [var.security_group_id]
publicly_accessible = false
# Monitoring
monitoring_interval = 60
monitoring_role_arn = aws_iam_role.rds_monitoring.arn
# Performance Insights
performance_insights_enabled = true
performance_insights_kms_key_id = aws_kms_key.rds.arn
skip_final_snapshot = true
tags = {
Name = "${var.project_name}-${var.environment}-db-read-replica"
Environment = var.environment
Project = var.project_name
}
}
EOF
cat > rds/outputs.tf << 'EOF'
output "db_instance_endpoint" {
description = "RDS instance endpoint"
value = aws_db_instance.main.endpoint
}
output "db_instance_id" {
description = "RDS instance ID"
value = aws_db_instance.main.id
}
output "db_instance_arn" {
description = "RDS instance ARN"
value = aws_db_instance.main.arn
}
output "db_instance_port" {
description = "RDS instance port"
value = aws_db_instance.main.port
}
output "db_subnet_group_id" {
description = "DB subnet group ID"
value = aws_db_subnet_group.main.id
}
output "db_parameter_group_id" {
description = "DB parameter group ID"
value = aws_db_parameter_group.main.id
}
output "read_replica_endpoint" {
description = "Read replica endpoint"
value = var.environment == "prod" ? aws_db_instance.read_replica[0].endpoint : null
}
EOF
🎯 3.6 Environment-Specific Configurations
# 3.6.1 Development environment
cd ~/devops-infrastructure/terraform/environments/dev
# SSH key pair oluştur
ssh-keygen -t rsa -b 4096 -C "devops@company.com" -f ~/.ssh/id_rsa -N ""
cat > main.tf << 'EOF'
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
# Backend configuration will be provided via backend config file
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "Terraform"
}
}
}
# Local values
locals {
cluster_name = "${var.project_name}-${var.environment}-eks"
}
# VPC Module
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
availability_zones = var.availability_zones
environment = var.environment
project_name = var.project_name
}
# Security Groups Module
module "security_groups" {
source = "../../modules/security-groups"
vpc_id = module.vpc.vpc_id
environment = var.environment
project_name = var.project_name
}
# EKS Module
module "eks" {
source = "../../modules/eks"
cluster_name = local.cluster_name
cluster_version = var.kubernetes_version
subnet_ids = concat(module.vpc.public_subnet_ids, module.vpc.private_subnet_ids)
node_subnet_ids = module.vpc.private_subnet_ids
cluster_security_group_id = module.security_groups.eks_cluster_security_group_id
node_security_group_id = module.security_groups.eks_nodes_security_group_id
environment = var.environment
project_name = var.project_name
}
# RDS Module
module "rds" {
source = "../../modules/rds"
db_name = var.db_name
db_username = var.db_username
db_password = var.db_password
subnet_ids = module.vpc.private_subnet_ids
security_group_id = module.security_groups.rds_security_group_id
environment = var.environment
project_name = var.project_name
engine = "postgres"
engine_version = "15.4"
instance_class = "db.t3.micro"
allocated_storage = 20
}
EOF
cat > variables.tf << 'EOF'
variable "aws_region" {
description = "AWS region"
type = string
default = "eu-west-1"
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
variable "project_name" {
description = "Project name"
type = string
default = "mycompany"
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
variable "availability_zones" {
description = "Availability zones"
type = list(string)
default = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
}
variable "kubernetes_version" {
description = "Kubernetes version"
type = string
default = "1.30"
}
variable "db_name" {
description = "Database name"
type = string
default = "mycompanydb"
}
variable "db_username" {
description = "Database username"
type = string
default = "admin"
}
variable "db_password" {
description = "Database password"
type = string
sensitive = true
}
EOF
cat > terraform.tfvars << 'EOF'
aws_region = "eu-west-1"
environment = "dev"
project_name = "mycompany"
vpc_cidr = "10.0.0.0/16"
availability_zones = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
kubernetes_version = "1.30"
db_name = "mycompanydb"
db_username = "admin"
db_password = "<DB_PASSWORD>" # tfvars'a düz yazma — prod: secret manager / TF_VAR_db_password env
EOF
cat > outputs.tf << 'EOF'
output "vpc_id" {
description = "VPC ID"
value = module.vpc.vpc_id
}
output "eks_cluster_endpoint" {
description = "EKS cluster endpoint"
value = module.eks.cluster_endpoint
}
output "eks_cluster_name" {
description = "EKS cluster name"
value = module.eks.cluster_id
}
output "rds_endpoint" {
description = "RDS endpoint"
value = module.rds.db_instance_endpoint
}
output "configure_kubectl" {
description = "Configure kubectl command"
value = "aws eks update-kubeconfig --region ${var.aws_region} --name ${module.eks.cluster_id}"
}
EOF
# Backend configuration
cat > backend.conf << EOF
bucket = "$TF_VAR_backend_bucket"
key = "dev/terraform.tfstate"
region = "$TF_VAR_backend_region"
dynamodb_table = "$TF_VAR_backend_dynamodb_table"
encrypt = true
EOF
# 3.7.1 Terraform initialize
cd ~/devops-infrastructure/terraform/environments/dev
terraform init -backend-config=backend.conf
# 3.7.2 Terraform plan
terraform plan -out=tfplan
# 3.7.3 Terraform apply
terraform apply tfplan
# 3.7.4 kubectl konfigürasyonu
aws eks update-kubeconfig --region eu-west-1 --name $(terraform output -raw eks_cluster_name)
# 3.7.5 Cluster bağlantısını test et
kubectl get nodes
kubectl get pods --all-namespaces
# 3.7.6 Terraform outputs
terraform output