feat(iac): modularize EC2 env + add dynamic AMI lookup
- new envs/dev-ec2 environment - add ami_lookup module (Ubuntu/Rocky/AmazonLinux auto-resolve) - add keypair, sg, ec2 modules - remove VPC remote_state dependency - fix SG duplicate rules - unify module variables/outputs
This commit is contained in:
parent
a75754a2ee
commit
7c57c839ef
@ -0,0 +1,23 @@
|
||||
name_prefix: "dev-ec2"
|
||||
|
||||
vpc_id: "vpc-0d0d8d822fa215104"
|
||||
subnet_id: "subnet-0c370f7ff7311388e"
|
||||
|
||||
instance:
|
||||
type: "t3.micro"
|
||||
ami: "ubuntu-2204"
|
||||
|
||||
keypair:
|
||||
name: "dev-key"
|
||||
public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDEsuS135lzjVvlH2iNrKz23lDFr7b686xs4d2HINP2glFPmgkgx1D6Dqwisb1UbhWHZmUUzRxXeNlE8fiaO0TXN/C0dsdUxgopnQRyakcA+gfJqqb38Syx8eqdC7mQy9ygOf763dWm6d/SYZ8WgNWLldk4QF9DiZOW9K22DMtY4/1Cqe/YE/WGpOMVr9T9BwvmOjarjWp2OPbx6RVlSOd735Mze5X+cJ9QqdLaisCiSoJ3j9S6dulcxm+7ghPfATvxlJyZWSrRrVqnmV45lPbeuUHlIEyuK1PK2MS6NtUP03ZhdRYJQKZLECpR5xAO/BliOtDdRornvHV1gutYD8/n3IS8sRVzYPvN9DuOhzBnBQUgciu2++R8zMfdVoH7mSbsE8u++vMcBk3UJ1Op0Ct+trl2bsnue96cAnoiII08JKwAaczD5uZIGhdkGV8zKnChNCjzCxP0i4PV/MYW04eWmH+E8G81zq4ZsvrvPYmilBbRrkwHvvbPba3SSb2F2As= shenlan@shenlandeMacBook-Air-2.local"
|
||||
|
||||
security_group:
|
||||
name: "dev-ec2-sg"
|
||||
ssh_cidr: "0.0.0.0/0"
|
||||
additional_ingress:
|
||||
- port: 80
|
||||
protocol: tcp
|
||||
cidr: "0.0.0.0/0"
|
||||
- port: 443
|
||||
protocol: tcp
|
||||
cidr: "0.0.0.0/0"
|
||||
25
iac-template/terraform-standard/envs/dev-ec2/.gitignore
vendored
Normal file
25
iac-template/terraform-standard/envs/dev-ec2/.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Local terraform files
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
|
||||
# Auto tfvars generated by CI/CD or sensitive data
|
||||
*.tfvars
|
||||
*.auto.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# IDE / editor files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
|
||||
# AWS credentials — never commit
|
||||
.aws/
|
||||
credentials
|
||||
config
|
||||
|
||||
# OS-specific
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
17
iac-template/terraform-standard/envs/dev-ec2/Makefile
Normal file
17
iac-template/terraform-standard/envs/dev-ec2/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
# envs/dev-ec2/Makefile
|
||||
|
||||
init:
|
||||
terraform init --upgrade
|
||||
|
||||
plan: init
|
||||
terraform plan
|
||||
|
||||
apply: init
|
||||
terraform apply -auto-approve
|
||||
|
||||
output:
|
||||
terraform output
|
||||
|
||||
destroy: init
|
||||
terraform destroy -auto-approve
|
||||
|
||||
9
iac-template/terraform-standard/envs/dev-ec2/backend.tf
Normal file
9
iac-template/terraform-standard/envs/dev-ec2/backend.tf
Normal file
@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "svc-plus-iac-state"
|
||||
key = "account/dev/iam/terraform.tfstate"
|
||||
region = "ap-northeast-1"
|
||||
dynamodb_table = "svc-plus-iac-state-dynamodb-lock"
|
||||
}
|
||||
}
|
||||
|
||||
41
iac-template/terraform-standard/envs/dev-ec2/main.tf
Normal file
41
iac-template/terraform-standard/envs/dev-ec2/main.tf
Normal file
@ -0,0 +1,41 @@
|
||||
locals {
|
||||
account = yamldecode(file("${path.root}/../../config/accounts/dev.yaml"))
|
||||
ec2_conf = yamldecode(file("${path.root}/../../config/resources/ec2/dev.yaml"))
|
||||
}
|
||||
|
||||
module "ami_lookup" {
|
||||
source = "../../modules/ami_lookup"
|
||||
name = local.ec2_conf.instance.ami
|
||||
region = local.account.region
|
||||
}
|
||||
|
||||
module "keypair" {
|
||||
source = "../../modules/keypair"
|
||||
name = local.ec2_conf.keypair.name
|
||||
public_key = local.ec2_conf.keypair.public_key
|
||||
tags = local.account.tags
|
||||
}
|
||||
|
||||
module "sg" {
|
||||
source = "../../modules/sg"
|
||||
|
||||
name = local.ec2_conf.security_group.name
|
||||
vpc_id = local.ec2_conf.vpc_id # <<<<<< 来自 YAML
|
||||
ssh_cidr = local.ec2_conf.security_group.ssh_cidr
|
||||
additional_ingress = local.ec2_conf.security_group.additional_ingress
|
||||
tags = local.account.tags
|
||||
}
|
||||
|
||||
module "ec2" {
|
||||
source = "../../modules/ec2"
|
||||
|
||||
name_prefix = local.ec2_conf.name_prefix
|
||||
instance = {
|
||||
type = local.ec2_conf.instance.type
|
||||
ami = module.ami_lookup.id # <<<<<< 自动解析 AMI
|
||||
}
|
||||
subnet_id = local.ec2_conf.subnet_id # <<<<<< 来自 YAML
|
||||
sg_id = module.sg.sg_id
|
||||
keypair_name = module.keypair.keypair_name
|
||||
tags = local.account.tags
|
||||
}
|
||||
24
iac-template/terraform-standard/envs/dev-ec2/outputs.tf
Normal file
24
iac-template/terraform-standard/envs/dev-ec2/outputs.tf
Normal file
@ -0,0 +1,24 @@
|
||||
output "instance_id" {
|
||||
description = "EC2 instance ID"
|
||||
value = module.ec2.instance_id
|
||||
}
|
||||
|
||||
output "public_ip" {
|
||||
description = "Public IP address of the EC2 instance"
|
||||
value = module.ec2.public_ip
|
||||
}
|
||||
|
||||
output "private_ip" {
|
||||
description = "Private IP address of the EC2 instance"
|
||||
value = module.ec2.private_ip
|
||||
}
|
||||
|
||||
output "keypair_name" {
|
||||
description = "KeyPair name used for the instance"
|
||||
value = module.keypair.keypair_name
|
||||
}
|
||||
|
||||
output "security_group_id" {
|
||||
description = "Security Group ID attached to the EC2 instance"
|
||||
value = module.sg.sg_id
|
||||
}
|
||||
20
iac-template/terraform-standard/envs/dev-ec2/provider.tf
Normal file
20
iac-template/terraform-standard/envs/dev-ec2/provider.tf
Normal file
@ -0,0 +1,20 @@
|
||||
terraform {
|
||||
required_version = ">= 1.2"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.92.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = local.account.region
|
||||
|
||||
assume_role {
|
||||
role_arn = "arn:aws:iam::730335654753:role/TerraformDeployRole-Dev"
|
||||
session_name = "TerraformDevSession"
|
||||
}
|
||||
}
|
||||
|
||||
7
iac-template/terraform-standard/envs/dev-vpc/README.md
Normal file
7
iac-template/terraform-standard/envs/dev-vpc/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
创建:
|
||||
✔ VPC
|
||||
✔ 2 Public Subnets
|
||||
✔ 2 Private Subnets
|
||||
✔ Internet Gateway
|
||||
✔ NAT Gateway
|
||||
✔ Public Route Table + Private Route Table
|
||||
60
iac-template/terraform-standard/modules/ami_lookup/main.tf
Normal file
60
iac-template/terraform-standard/modules/ami_lookup/main.tf
Normal file
@ -0,0 +1,60 @@
|
||||
locals {
|
||||
name = var.name
|
||||
|
||||
# OS type flags
|
||||
is_ubuntu_2204 = local.name == "ubuntu_2204"
|
||||
is_ubuntu_2404 = local.name == "ubuntu_2404"
|
||||
is_rocky_8 = local.name == "rocky_8"
|
||||
is_rocky_9 = local.name == "rocky_9"
|
||||
is_rocky_10 = local.name == "rocky_10"
|
||||
is_amzn2 = local.name == "amazonlinux_2"
|
||||
|
||||
# Filters(每种 OS 一个准确 pattern)
|
||||
ami_filters = (
|
||||
local.is_ubuntu_2204 ? [
|
||||
"ubuntu/images/hvm-ssd-gp3/ubuntu-jammy-22.04-amd64-server-*"
|
||||
] :
|
||||
local.is_ubuntu_2404 ? [
|
||||
"ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"
|
||||
] :
|
||||
local.is_rocky_8 ? [
|
||||
"Rocky-8-*-x86_64-*"
|
||||
] :
|
||||
local.is_rocky_9 ? [
|
||||
"Rocky-9-*-x86_64-*"
|
||||
] :
|
||||
local.is_rocky_10 ? [
|
||||
"Rocky-10-*-x86_64-*"
|
||||
] :
|
||||
local.is_amzn2 ? [
|
||||
"amzn2-ami-hvm-*-x86_64-gp2"
|
||||
] :
|
||||
["*"]
|
||||
)
|
||||
|
||||
# AMI Owner IDs
|
||||
ami_owners = (
|
||||
(local.is_rocky_8 || local.is_rocky_9 || local.is_rocky_10) ? ["679593333241"] :
|
||||
(local.is_ubuntu_2204 || local.is_ubuntu_2404) ? ["099720109477"] :
|
||||
local.is_amzn2 ? ["137112412989"] :
|
||||
["amazon"]
|
||||
)
|
||||
}
|
||||
|
||||
data "aws_ami" "selected" {
|
||||
most_recent = true
|
||||
owners = local.ami_owners
|
||||
|
||||
dynamic "filter" {
|
||||
for_each = local.ami_filters
|
||||
content {
|
||||
name = "name"
|
||||
values = [filter.value]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "ami_id" {
|
||||
value = data.aws_ami.selected.id
|
||||
description = "Resolved AMI ID"
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
output "id" {
|
||||
description = "Resolved AMI ID"
|
||||
value = data.aws_ami.selected.id
|
||||
}
|
||||
|
||||
output "name" {
|
||||
description = "Resolved AMI name"
|
||||
value = data.aws_ami.selected.name
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
variable "name" {
|
||||
description = "Short AMI name, e.g. ubuntu-2204 | ubuntu-2404 | rocky-8 | amazonlinux-2"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "AWS region"
|
||||
type = string
|
||||
}
|
||||
|
||||
15
iac-template/terraform-standard/modules/ec2/main.tf
Normal file
15
iac-template/terraform-standard/modules/ec2/main.tf
Normal file
@ -0,0 +1,15 @@
|
||||
resource "aws_instance" "this" {
|
||||
ami = var.instance.ami
|
||||
instance_type = var.instance.type
|
||||
|
||||
# 明确由 env 层传入,无任何自动推断
|
||||
subnet_id = var.subnet_id
|
||||
|
||||
vpc_security_group_ids = [var.sg_id]
|
||||
|
||||
key_name = var.keypair_name
|
||||
|
||||
tags = merge(var.tags, {
|
||||
Name = "${var.name_prefix}-instance"
|
||||
})
|
||||
}
|
||||
24
iac-template/terraform-standard/modules/ec2/outputs.tf
Normal file
24
iac-template/terraform-standard/modules/ec2/outputs.tf
Normal file
@ -0,0 +1,24 @@
|
||||
output "instance_id" {
|
||||
description = "EC2 instance ID"
|
||||
value = aws_instance.this.id
|
||||
}
|
||||
|
||||
output "instance_arn" {
|
||||
description = "EC2 instance ARN"
|
||||
value = aws_instance.this.arn
|
||||
}
|
||||
|
||||
output "public_ip" {
|
||||
description = "Public IPv4 address"
|
||||
value = aws_instance.this.public_ip
|
||||
}
|
||||
|
||||
output "private_ip" {
|
||||
description = "Private IPv4 address"
|
||||
value = aws_instance.this.private_ip
|
||||
}
|
||||
|
||||
output "subnet_id" {
|
||||
description = "Instance subnet ID"
|
||||
value = aws_instance.this.subnet_id
|
||||
}
|
||||
32
iac-template/terraform-standard/modules/ec2/variables.tf
Normal file
32
iac-template/terraform-standard/modules/ec2/variables.tf
Normal file
@ -0,0 +1,32 @@
|
||||
variable "name_prefix" {
|
||||
type = string
|
||||
description = "Prefix for EC2 Name tag"
|
||||
}
|
||||
|
||||
variable "instance" {
|
||||
type = object({
|
||||
type = string
|
||||
ami = string
|
||||
})
|
||||
description = "Instance config"
|
||||
}
|
||||
|
||||
variable "subnet_id" {
|
||||
type = string
|
||||
description = "Subnet ID where EC2 instance will be launched"
|
||||
}
|
||||
|
||||
variable "sg_id" {
|
||||
type = string
|
||||
description = "Security Group ID"
|
||||
}
|
||||
|
||||
variable "keypair_name" {
|
||||
type = string
|
||||
description = "KeyPair name"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
type = map(string)
|
||||
description = "Common tags"
|
||||
}
|
||||
9
iac-template/terraform-standard/modules/keypair/main.tf
Normal file
9
iac-template/terraform-standard/modules/keypair/main.tf
Normal file
@ -0,0 +1,9 @@
|
||||
resource "aws_key_pair" "this" {
|
||||
key_name = var.name
|
||||
public_key = var.public_key
|
||||
|
||||
tags = merge(var.tags, {
|
||||
Name = var.name
|
||||
})
|
||||
}
|
||||
|
||||
10
iac-template/terraform-standard/modules/keypair/outputs.tf
Normal file
10
iac-template/terraform-standard/modules/keypair/outputs.tf
Normal file
@ -0,0 +1,10 @@
|
||||
output "keypair_name" {
|
||||
description = "The name of the AWS KeyPair"
|
||||
value = aws_key_pair.this.key_name
|
||||
}
|
||||
|
||||
output "fingerprint" {
|
||||
description = "KeyPair fingerprint"
|
||||
value = aws_key_pair.this.fingerprint
|
||||
}
|
||||
|
||||
14
iac-template/terraform-standard/modules/keypair/variables.tf
Normal file
14
iac-template/terraform-standard/modules/keypair/variables.tf
Normal file
@ -0,0 +1,14 @@
|
||||
variable "name" {
|
||||
description = "Name of the KeyPair"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "public_key" {
|
||||
description = "Public key material for AWS KeyPair"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Common tags"
|
||||
type = map(string)
|
||||
}
|
||||
25
iac-template/terraform-standard/modules/sg/.gitignore
vendored
Normal file
25
iac-template/terraform-standard/modules/sg/.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Local terraform files
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
|
||||
# Auto tfvars generated by CI/CD or sensitive data
|
||||
*.tfvars
|
||||
*.auto.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# IDE / editor files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
|
||||
# AWS credentials — never commit
|
||||
.aws/
|
||||
credentials
|
||||
config
|
||||
|
||||
# OS-specific
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
42
iac-template/terraform-standard/modules/sg/main.tf
Normal file
42
iac-template/terraform-standard/modules/sg/main.tf
Normal file
@ -0,0 +1,42 @@
|
||||
resource "aws_security_group" "this" {
|
||||
name = var.name
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
tags = merge(var.tags, {
|
||||
Name = var.name
|
||||
})
|
||||
}
|
||||
|
||||
# Merge SSH rule + additional_ingress → 单一入口
|
||||
locals {
|
||||
ingress_rules = concat(
|
||||
length(var.ssh_cidr) > 0 ? [
|
||||
{
|
||||
port = 22
|
||||
protocol = "tcp"
|
||||
cidr = var.ssh_cidr
|
||||
}
|
||||
] : [],
|
||||
var.additional_ingress
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_security_group_rule" "ingress" {
|
||||
for_each = { for idx, rule in local.ingress_rules : idx => rule }
|
||||
|
||||
type = "ingress"
|
||||
from_port = each.value.port
|
||||
to_port = each.value.port
|
||||
protocol = each.value.protocol
|
||||
cidr_blocks = [each.value.cidr]
|
||||
security_group_id = aws_security_group.this.id
|
||||
}
|
||||
|
||||
resource "aws_security_group_rule" "egress" {
|
||||
type = "egress"
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
security_group_id = aws_security_group.this.id
|
||||
}
|
||||
14
iac-template/terraform-standard/modules/sg/outputs.tf
Normal file
14
iac-template/terraform-standard/modules/sg/outputs.tf
Normal file
@ -0,0 +1,14 @@
|
||||
output "sg_id" {
|
||||
description = "Security Group ID"
|
||||
value = aws_security_group.this.id
|
||||
}
|
||||
|
||||
output "sg_name" {
|
||||
description = "Security Group Name"
|
||||
value = aws_security_group.this.name
|
||||
}
|
||||
|
||||
output "sg_arn" {
|
||||
description = "ARN of the Security Group"
|
||||
value = aws_security_group.this.arn
|
||||
}
|
||||
29
iac-template/terraform-standard/modules/sg/variables.tf
Normal file
29
iac-template/terraform-standard/modules/sg/variables.tf
Normal file
@ -0,0 +1,29 @@
|
||||
variable "name" {
|
||||
description = "Security Group name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vpc_id" {
|
||||
description = "VPC ID for the Security Group"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "ssh_cidr" {
|
||||
description = "CIDR allowed to SSH"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "additional_ingress" {
|
||||
description = "Additional ingress rules"
|
||||
type = list(object({
|
||||
port = number
|
||||
protocol = string
|
||||
cidr = string
|
||||
}))
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Common tags"
|
||||
type = map(string)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user