Created
December 17, 2025 06:29
-
-
Save tbvinh/ff03ea0f3ff821842ef25810cd9a8815 to your computer and use it in GitHub Desktop.
aws-script.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # --- Cấu hình dự án --- | |
| PROJECT_DIR="mva_terraform_project" | |
| echo "Bắt đầu tạo cấu trúc dự án Terraform tại thư mục: $PROJECT_DIR" | |
| # 1. Tạo thư mục gốc | |
| mkdir -p $PROJECT_DIR | |
| cd $PROJECT_DIR | |
| # 2. Tạo cấu trúc thư mục modules | |
| mkdir -p modules/{vpc,stateful,ecs-alb} | |
| echo "Đang tạo các file gốc (.tf) và variables..." | |
| # 3. Tạo các file gốc (.tf) | |
| cat << EOF > main.tf | |
| # File: main.tf | |
| module "vpc" { | |
| source = "./modules/vpc" | |
| app_name = var.app_name | |
| } | |
| module "stateful" { | |
| source = "./modules/stateful" | |
| app_name = var.app_name | |
| vpc_id = module.vpc.vpc_id | |
| database_subnet_ids = module.vpc.database_subnet_ids | |
| private_app_subnet_ids = module.vpc.private_app_subnet_ids | |
| db_username = var.db_username | |
| db_password = var.db_password | |
| } | |
| module "ecs_alb" { | |
| source = "./modules/ecs-alb" | |
| app_name = var.app_name | |
| vpc_id = module.vpc.vpc_id | |
| public_subnet_ids = module.vpc.public_subnet_ids | |
| private_app_subnet_ids = module.vpc.private_app_subnet_ids | |
| rds_endpoint = module.stateful.rds_endpoint | |
| redis_endpoint = module.stateful.redis_endpoint | |
| opensearch_endpoint = module.stateful.opensearch_endpoint | |
| } | |
| EOF | |
| cat << EOF > provider.tf | |
| # File: provider.tf | |
| terraform { | |
| required_providers { | |
| aws = { | |
| source = "hashicorp/aws" | |
| version = "~> 5.0" | |
| } | |
| } | |
| } | |
| provider "aws" { | |
| region = "ap-southeast-1" | |
| } | |
| EOF | |
| cat << EOF > variables.tf | |
| # File: variables.tf | |
| variable "db_username" { | |
| description = "Tên người dùng PostgreSQL" | |
| default = "dbadmin" | |
| } | |
| variable "db_password" { | |
| description = "Mật khẩu PostgreSQL" | |
| default = "DevPassword123!" | |
| sensitive = true | |
| } | |
| variable "app_name" { | |
| description = "Tên prefix cho các tài nguyên" | |
| default = "mva-app" | |
| } | |
| EOF | |
| echo "Đang tạo nội dung module VPC..." | |
| # 4. Nội dung Module VPC | |
| cat << EOF > modules/vpc/main.tf | |
| # File: modules/vpc/main.tf | |
| variable "app_name" {} | |
| locals { | |
| # 2 AZs cho cấu hình tối giản | |
| azs = ["ap-southeast-1a", "ap-southeast-1b"] | |
| } | |
| resource "aws_vpc" "main" { | |
| cidr_block = "10.0.0.0/16" | |
| enable_dns_hostnames = true | |
| tags = { Name = "\${var.app_name}-vpc" } | |
| } | |
| resource "aws_internet_gateway" "igw" { | |
| vpc_id = aws_vpc.main.id | |
| } | |
| resource "aws_subnet" "public" { | |
| count = length(local.azs) | |
| vpc_id = aws_vpc.main.id | |
| cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index) | |
| availability_zone = local.azs[count.index] | |
| map_public_ip_on_launch = true | |
| tags = { Name = "\${var.app_name}-public-\${count.index}" } | |
| } | |
| resource "aws_subnet" "private_app" { | |
| count = length(local.azs) | |
| vpc_id = aws_vpc.main.id | |
| cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 2) | |
| availability_zone = local.azs[count.index] | |
| tags = { Name = "\${var.app_name}-app-\${count.index}" } | |
| } | |
| resource "aws_subnet" "database" { | |
| count = length(local.azs) | |
| vpc_id = aws_vpc.main.id | |
| cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 4) | |
| availability_zone = local.azs[count.index] | |
| tags = { Name = "\${var.app_name}-db-\${count.index}" } | |
| } | |
| resource "aws_route_table" "public" { | |
| vpc_id = aws_vpc.main.id | |
| route { | |
| cidr_block = "0.0.0.0/0" | |
| gateway_id = aws_internet_gateway.igw.id | |
| } | |
| } | |
| 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 | |
| } | |
| EOF | |
| cat << EOF > modules/vpc/outputs.tf | |
| output "vpc_id" { value = aws_vpc.main.id } | |
| output "public_subnet_ids" { value = aws_subnet.public[*].id } | |
| output "private_app_subnet_ids" { value = aws_subnet.private_app[*].id } | |
| output "database_subnet_ids" { value = aws_subnet.database[*].id } | |
| EOF | |
| echo "Đang tạo nội dung module Stateful (Dữ liệu)..." | |
| # 5. Nội dung Module Stateful | |
| cat << EOF > modules/stateful/variables.tf | |
| variable "app_name" {} | |
| variable "vpc_id" {} | |
| variable "database_subnet_ids" { type = list(string) } | |
| variable "private_app_subnet_ids" { type = list(string) } | |
| variable "db_username" {} | |
| variable "db_password" {} | |
| EOF | |
| cat << EOF > modules/stateful/main.tf | |
| # File: modules/stateful/main.tf | |
| resource "aws_security_group" "data_tier_sg" { | |
| name = "\${var.app_name}-data-tier-sg" | |
| vpc_id = var.vpc_id | |
| ingress { | |
| from_port = 0 | |
| to_port = 0 | |
| protocol = "-1" | |
| cidr_blocks = var.private_app_subnet_ids | |
| } | |
| egress { from_port = 0; to_port = 0; protocol = "-1"; cidr_blocks = ["0.0.0.0/0"] } | |
| } | |
| resource "aws_db_subnet_group" "rds_group" { | |
| name = "\${var.app_name}-rds-group" | |
| subnet_ids = var.database_subnet_ids | |
| } | |
| resource "aws_db_instance" "postgres" { | |
| identifier = "\${var.app_name}-db" | |
| instance_class = "db.t3.micro" | |
| multi_az = false # Tắt HA | |
| username = var.db_username | |
| password = var.db_password | |
| db_name = "appdb" | |
| vpc_security_group_ids = [aws_security_group.data_tier_sg.id] | |
| db_subnet_group_name = aws_db_subnet_group.rds_group.name | |
| skip_final_snapshot = true | |
| } | |
| resource "aws_elasticache_subnet_group" "cache_group" { | |
| name = "\${var.app_name}-cache-group" | |
| subnet_ids = var.database_subnet_ids | |
| } | |
| resource "aws_elasticache_replication_group" "redis" { | |
| replication_group_id = "\${var.app_name}-redis" | |
| node_type = "cache.t3.micro" | |
| num_cache_clusters = 1 | |
| automatic_failover_enabled = false # Tắt HA | |
| subnet_group_name = aws_elasticache_subnet_group.cache_group.name | |
| security_group_ids = [aws_security_group.data_tier_sg.id] | |
| } | |
| resource "aws_opensearch_domain" "es" { | |
| domain_name = "\${var.app_name}-es" | |
| engine_version = "OpenSearch_2.5" | |
| cluster_config { | |
| instance_type = "t3.small.search" | |
| instance_count = 1 | |
| } | |
| vpc_options { | |
| subnet_ids = var.database_subnet_ids | |
| security_group_ids = [aws_security_group.data_tier_sg.id] | |
| } | |
| access_policies = jsonencode({ | |
| Version = "2012-10-17" | |
| Statement = [{ | |
| Effect = "Allow" | |
| Principal = { AWS = "*" } | |
| Action = "es:*" | |
| Resource = "arn:aws:es:*:*:domain/\${var.app_name}-es/*" | |
| }] | |
| }) | |
| } | |
| output "rds_endpoint" { value = aws_db_instance.postgres.address } | |
| output "redis_endpoint" { value = aws_elasticache_replication_group.redis.primary_endpoint_address } | |
| output "opensearch_endpoint" { value = aws_opensearch_domain.es.endpoint } | |
| EOF | |
| echo "Đang tạo nội dung module ECS/ALB (Ứng dụng)..." | |
| # 6. Nội dung Module ECS/ALB | |
| cat << EOF > modules/ecs-alb/variables.tf | |
| variable "app_name" {} | |
| variable "vpc_id" {} | |
| variable "public_subnet_ids" { type = list(string) } | |
| variable "private_app_subnet_ids" { type = list(string) } | |
| variable "rds_endpoint" {} | |
| variable "redis_endpoint" {} | |
| variable "opensearch_endpoint" {} | |
| EOF | |
| cat << EOF > modules/ecs-alb/task-definition.json.tpl | |
| { | |
| "containerDefinitions": [ | |
| { | |
| "name": "nginx-container", | |
| "image": "\${nginx_image_uri}", | |
| "portMappings": [ { "containerPort": 80, "hostPort": 80 } ], | |
| "essential": true | |
| }, | |
| { | |
| "name": "php-fpm-container", | |
| "image": "\${php_fpm_image_uri}", | |
| "portMappings": [ { "containerPort": 9000, "hostPort": 9000 } ], | |
| "essential": true, | |
| "environment": [ | |
| {"name": "DB_HOST", "value": "\${rds_host}"}, | |
| {"name": "DB_USER", "value": "dbadmin"}, | |
| {"name": "DB_PASSWORD", "value": "DevPassword123!"}, | |
| {"name": "REDIS_HOST", "value": "\${redis_host}"}, | |
| {"name": "OPENSEARCH_HOST", "value": "\${opensearch_host}"} | |
| ] | |
| } | |
| ] | |
| } | |
| EOF | |
| cat << EOF > modules/ecs-alb/main.tf | |
| # File: modules/ecs-alb/main.tf | |
| # --- 1. ECR Repositories --- | |
| resource "aws_ecr_repository" "nginx_repo" { name = "\${var.app_name}-nginx-repo" } | |
| resource "aws_ecr_repository" "php_fpm_repo" { name = "\${var.app_name}-php-fpm-repo" } | |
| # --- 2. ECS Cluster --- | |
| resource "aws_ecs_cluster" "main" { name = "\${var.app_name}-cluster" } | |
| # --- 3. Task Definition --- | |
| data "template_file" "php_nginx_task" { | |
| template = file("\${path.module}/task-definition.json.tpl") | |
| vars = { | |
| rds_host = var.rds_endpoint | |
| redis_host = var.redis_endpoint | |
| opensearch_host = var.opensearch_endpoint | |
| nginx_image_uri = aws_ecr_repository.nginx_repo.repository_url | |
| php_fpm_image_uri = aws_ecr_repository.php_fpm_repo.repository_url | |
| } | |
| } | |
| resource "aws_ecs_task_definition" "php_nginx" { | |
| family = "\${var.app_name}-php-nginx-task" | |
| network_mode = "awsvpc" | |
| requires_compatibilities = ["FARGATE"] | |
| cpu = 1024 | |
| memory = 2048 | |
| container_definitions = data.template_file.php_nginx_task.rendered | |
| # Cần thêm execution_role_arn và task_role_arn (đã đơn giản hóa) | |
| } | |
| # --- 4. Security Groups --- | |
| resource "aws_security_group" "alb_sg" { | |
| name = "\${var.app_name}-alb-sg" | |
| vpc_id = var.vpc_id | |
| ingress { from_port = 80; to_port = 80; 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"] } | |
| } | |
| resource "aws_security_group" "ecs_sg" { | |
| name = "\${var.app_name}-ecs-sg" | |
| vpc_id = var.vpc_id | |
| # Cho phép ALB truy cập ECS Task trên cổng 80 | |
| ingress { from_port = 80; to_port = 80; protocol = "tcp"; security_groups = [aws_security_group.alb_sg.id] } | |
| egress { from_port = 0; to_port = 0; protocol = "-1"; cidr_blocks = ["0.0.0.0/0"] } | |
| } | |
| # --- 5. ALB và Target Groups --- | |
| resource "aws_lb" "main" { | |
| name = "\${var.app_name}-alb" | |
| internal = false | |
| load_balancer_type = "application" | |
| security_groups = [aws_security_group.alb_sg.id] | |
| subnets = var.public_subnet_ids | |
| } | |
| resource "aws_lb_target_group" "tg_app" { name = "\${var.app_name}-tg-app"; port = 80; vpc_id = var.vpc_id; target_type = "ip" } | |
| resource "aws_lb_target_group" "tg_ws" { name = "\${var.app_name}-tg-ws"; port = 80; vpc_id = var.vpc_id; target_type = "ip" } | |
| # Listener | |
| resource "aws_lb_listener" "http_listener" { | |
| load_balancer_arn = aws_lb.main.arn | |
| port = 80 | |
| protocol = "HTTP" | |
| default_action { type = "forward"; target_group_arn = aws_lb_target_group.tg_app.arn } | |
| } | |
| # Giả định www.domain.com trỏ đến TG-APP | |
| # Giả định ws.domain.com trỏ đến TG-WS (WebSockets) | |
| resource "aws_lb_listener_rule" "ws_rule" { | |
| listener_arn = aws_lb_listener.http_listener.arn | |
| priority = 10 | |
| action { type = "forward"; target_group_arn = aws_lb_target_group.tg_ws.arn } | |
| condition { host_header { values = ["ws.domain.com"] } } | |
| } | |
| # --- 6. ECS Service --- | |
| resource "aws_ecs_service" "main" { | |
| name = "\${var.app_name}-service" | |
| cluster = aws_ecs_cluster.main.id | |
| task_definition = aws_ecs_task_definition.php_nginx.arn | |
| desired_count = 1 # TỐI GIẢN: Chỉ 1 Task | |
| launch_type = "FARGATE" | |
| network_configuration { | |
| subnets = var.private_app_subnet_ids | |
| security_groups = [aws_security_group.ecs_sg.id] | |
| assign_public_ip = false | |
| } | |
| load_balancer { | |
| target_group_arn = aws_lb_target_group.tg_app.arn | |
| container_name = "nginx-container" | |
| container_port = 80 | |
| } | |
| } | |
| EOF | |
| echo "Hoàn tất tạo dự án Terraform tại \$(pwd)" | |
| echo "--- Các bước tiếp theo ---" | |
| echo "1. Chuyển vào thư mục: cd $PROJECT_DIR" | |
| echo "2. Chỉnh sửa mật khẩu DB trong variables.tf nếu cần." | |
| echo "3. Chạy lệnh: terraform init" | |
| echo "4. Chạy lệnh: terraform apply" | |
| echo "5. Sau khi thử nghiệm, chạy lệnh: terraform destroy (để tránh phí)." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment