Skip to main content

Infrastructure as Code with Terraform

Complete guide for managing SBM CRM Platform infrastructure using Terraform on Huawei Cloud.

Prerequisites

  • Terraform >= 1.0
  • Huawei Cloud account
  • Access key and secret key
  • Basic knowledge of Terraform

Terraform Configuration

Provider Configuration

Create providers.tf:

terraform {
required_version = ">= 1.0"

required_providers {
huaweicloud = {
source = "huaweicloud/huaweicloud"
version = "~> 1.40"
}
}

backend "s3" {
# Use OBS for state storage
bucket = "sbmcrm-terraform-state"
key = "terraform.tfstate"
region = "ap-southeast-1"
}
}

provider "huaweicloud" {
region = var.region
access_key = var.access_key
secret_key = var.secret_key
}

Variables

Create variables.tf:

variable "region" {
description = "Huawei Cloud region"
type = string
default = "ap-southeast-1"
}

variable "access_key" {
description = "Huawei Cloud access key"
type = string
sensitive = true
}

variable "secret_key" {
description = "Huawei Cloud secret key"
type = string
sensitive = true
}

variable "project_name" {
description = "Project name"
type = string
default = "sbmcrm"
}

variable "environment" {
description = "Environment (production, staging, development)"
type = string
default = "production"
}

variable "vpc_cidr" {
description = "VPC CIDR block"
type = string
default = "10.0.0.0/16"
}

variable "availability_zones" {
description = "Availability zones"
type = list(string)
default = ["ap-southeast-1a", "ap-southeast-1b"]
}

VPC and Networking

Create network.tf:

# VPC
resource "huaweicloud_vpc" "main" {
name = "${var.project_name}-vpc"
cidr = var.vpc_cidr
}

# Public Subnet A
resource "huaweicloud_vpc_subnet" "public_a" {
name = "${var.project_name}-public-subnet-a"
cidr = "10.0.1.0/24"
gateway_ip = "10.0.1.1"
vpc_id = huaweicloud_vpc.main.id
availability_zone = var.availability_zones[0]

dns_list = [
"100.125.1.250",
"100.125.129.250"
]
}

# Public Subnet B
resource "huaweicloud_vpc_subnet" "public_b" {
name = "${var.project_name}-public-subnet-b"
cidr = "10.0.2.0/24"
gateway_ip = "10.0.2.1"
vpc_id = huaweicloud_vpc.main.id
availability_zone = var.availability_zones[1]

dns_list = [
"100.125.1.250",
"100.125.129.250"
]
}

# Private Subnet A
resource "huaweicloud_vpc_subnet" "private_a" {
name = "${var.project_name}-private-subnet-a"
cidr = "10.0.10.0/24"
gateway_ip = "10.0.10.1"
vpc_id = huaweicloud_vpc.main.id
availability_zone = var.availability_zones[0]

dns_list = [
"100.125.1.250",
"100.125.129.250"
]
}

# Private Subnet B
resource "huaweicloud_vpc_subnet" "private_b" {
name = "${var.project_name}-private-subnet-b"
cidr = "10.0.11.0/24"
gateway_ip = "10.0.11.1"
vpc_id = huaweicloud_vpc.main.id
availability_zone = var.availability_zones[1]

dns_list = [
"100.125.1.250",
"100.125.129.250"
]
}

Security Groups

Create security_groups.tf:

# Application Security Group
resource "huaweicloud_networking_secgroup" "app" {
name = "${var.project_name}-app-sg"
description = "Security group for application servers"
}

resource "huaweicloud_networking_secgroup_rule" "app_http" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 80
port_range_max = 80
remote_group_id = huaweicloud_networking_secgroup.elb.id
security_group_id = huaweicloud_networking_secgroup.app.id
}

resource "huaweicloud_networking_secgroup_rule" "app_https" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 443
port_range_max = 443
remote_group_id = huaweicloud_networking_secgroup.elb.id
security_group_id = huaweicloud_networking_secgroup.app.id
}

resource "huaweicloud_networking_secgroup_rule" "app_ssh" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "203.0.113.0/24" # Management IPs
security_group_id = huaweicloud_networking_secgroup.app.id
}

# Database Security Group
resource "huaweicloud_networking_secgroup" "db" {
name = "${var.project_name}-db-sg"
description = "Security group for database"
}

resource "huaweicloud_networking_secgroup_rule" "db_postgres" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 5432
port_range_max = 5432
remote_group_id = huaweicloud_networking_secgroup.app.id
security_group_id = huaweicloud_networking_secgroup.db.id
}

# Cache Security Group
resource "huaweicloud_networking_secgroup" "cache" {
name = "${var.project_name}-cache-sg"
description = "Security group for Redis cache"
}

resource "huaweicloud_networking_secgroup_rule" "cache_redis" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 6379
port_range_max = 6379
remote_group_id = huaweicloud_networking_secgroup.app.id
security_group_id = huaweicloud_networking_secgroup.cache.id
}

ECS Instances

Create ecs.tf:

# Key Pair
resource "huaweicloud_kps_keypair" "main" {
name = "${var.project_name}-keypair"
}

# ECS Instance 1
resource "huaweicloud_compute_instance" "api_01" {
name = "${var.project_name}-api-01"
image_id = "ubuntu_20_04_64bit"
flavor_id = "s6.xlarge.2"
availability_zone = var.availability_zones[0]
key_pair = huaweicloud_kps_keypair.main.name

network {
uuid = huaweicloud_vpc_subnet.public_a.id
}

security_groups = [
huaweicloud_networking_secgroup.app.id
]

system_disk_type = "SSD"
system_disk_size = 100

user_data = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y docker.io docker-compose
systemctl enable docker
systemctl start docker
EOF

tags = {
Environment = var.environment
Role = "api-server"
}
}

# ECS Instance 2
resource "huaweicloud_compute_instance" "api_02" {
name = "${var.project_name}-api-02"
image_id = "ubuntu_20_04_64bit"
flavor_id = "s6.xlarge.2"
availability_zone = var.availability_zones[1]
key_pair = huaweicloud_kps_keypair.main.name

network {
uuid = huaweicloud_vpc_subnet.public_b.id
}

security_groups = [
huaweicloud_networking_secgroup.app.id
]

system_disk_type = "SSD"
system_disk_size = 100

user_data = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y docker.io docker-compose
systemctl enable docker
systemctl start docker
EOF

tags = {
Environment = var.environment
Role = "api-server"
}
}

RDS Database

Create rds.tf:

resource "huaweicloud_rds_instance" "postgresql" {
name = "${var.project_name}-postgresql"
flavor = "rds.pg.c2.xlarge"
ha_replication_mode = "async"
vpc_id = huaweicloud_vpc.main.id
subnet_id = huaweicloud_vpc_subnet.private_a.id
security_group_id = huaweicloud_networking_secgroup.db.id
availability_zone = [
var.availability_zones[0],
var.availability_zones[1]
]

db {
type = "PostgreSQL"
version = "13"
password = var.db_password
port = 5432
}

volume {
type = "ULTRAHIGH"
size = 500
}

backup_strategy {
start_time = "02:00-03:00"
keep_days = 30
}

tags = {
Environment = var.environment
}
}

resource "huaweicloud_rds_database" "main" {
instance_id = huaweicloud_rds_instance.postgresql.id
name = "sbmcrm_production"
character_set = "UTF8"
}

resource "huaweicloud_rds_account" "main" {
instance_id = huaweicloud_rds_instance.postgresql.id
name = "sbmcrm"
password = var.db_user_password
}

Redis Cache

Create redis.tf:

resource "huaweicloud_dcs_instance" "redis" {
name = "${var.project_name}-redis"
engine_version = "6.0"
password = var.redis_password
capacity = 8
vpc_id = huaweicloud_vpc.main.id
subnet_id = huaweicloud_vpc_subnet.private_a.id
security_group_id = huaweicloud_networking_secgroup.cache.id
availability_zones = [var.availability_zones[0]]

backup_policy {
save_days = 7
backup_type = "auto"
period_type = "weekly"
begin_at = "00:00-01:00"
backup_at = [1, 2, 3, 4, 5, 6, 7]
}

tags = {
Environment = var.environment
}
}

ELB Load Balancer

Create elb.tf:

resource "huaweicloud_elb_loadbalancer" "main" {
name = "${var.project_name}-elb"
vpc_id = huaweicloud_vpc.main.id
ipv4_subnet_id = huaweicloud_vpc_subnet.public_a.id
ipv6_subnet_id = huaweicloud_vpc_subnet.public_b.id
l4_flavor_id = "elb.s2.medium"
l7_flavor_id = "elb.s2.medium"

availability_zone = var.availability_zones
}

resource "huaweicloud_elb_listener" "https" {
name = "${var.project_name}-https-listener"
protocol = "HTTPS"
protocol_port = 443
loadbalancer_id = huaweicloud_elb_loadbalancer.main.id
server_certificate_id = var.ssl_certificate_id

default_pool_id = huaweicloud_elb_pool.main.id
}

resource "huaweicloud_elb_pool" "main" {
name = "${var.project_name}-backend-pool"
protocol = "HTTP"
lb_method = "ROUND_ROBIN"
listener_id = huaweicloud_elb_listener.https.id

persistence {
type = "APP_COOKIE"
cookie_name = "JSESSIONID"
}

health_check {
protocol = "HTTP"
delay = 30
timeout = 5
max_retries = 3
url_path = "/health"
}
}

resource "huaweicloud_elb_member" "api_01" {
address = huaweicloud_compute_instance.api_01.access_ip_v4
protocol_port = 3000
pool_id = huaweicloud_elb_pool.main.id
subnet_id = huaweicloud_vpc_subnet.public_a.id
}

resource "huaweicloud_elb_member" "api_02" {
address = huaweicloud_compute_instance.api_02.access_ip_v4
protocol_port = 3000
pool_id = huaweicloud_elb_pool.main.id
subnet_id = huaweicloud_vpc_subnet.public_b.id
}

Outputs

Create outputs.tf:

output "vpc_id" {
value = huaweicloud_vpc.main.id
}

output "elb_ip" {
value = huaweicloud_elb_loadbalancer.main.ipv4_address
}

output "ecs_instance_ips" {
value = [
huaweicloud_compute_instance.api_01.access_ip_v4,
huaweicloud_compute_instance.api_02.access_ip_v4
]
}

output "rds_endpoint" {
value = huaweicloud_rds_instance.postgresql.private_ips[0]
}

output "redis_endpoint" {
value = huaweicloud_dcs_instance.redis.ip
}

Usage

Initialize Terraform

terraform init

Plan Changes

terraform plan -var-file=production.tfvars

Apply Configuration

terraform apply -var-file=production.tfvars

Destroy Infrastructure

terraform destroy -var-file=production.tfvars

Environment-Specific Configurations

production.tfvars

environment = "production"
region = "ap-southeast-1"
vpc_cidr = "10.0.0.0/16"

staging.tfvars

environment = "staging"
region = "ap-southeast-1"
vpc_cidr = "10.1.0.0/16"

Best Practices

  1. State Management: Use remote state (OBS) for team collaboration
  2. Variables: Use .tfvars files for environment-specific values
  3. Modules: Create reusable modules for common patterns
  4. Versioning: Pin provider versions
  5. Secrets: Use environment variables or secret management for sensitive data
  6. Documentation: Document all resources and their purposes
  7. Testing: Test changes in staging before production

Next Steps

  1. Review Cloud Architecture for manual setup
  2. Configure Networking for network details
  3. Set up High Availability configuration