Skip to content
Search RunEntLinux

Searches general documentation on RunEntLinux. Each distribution has its own documentation search.

    Browse this documentation

    Terraform is an Infrastructure as Code (IaC) tool developed by HashiCorp. It uses the declarative configuration language HCL (HashiCorp Configuration Language) to define and manage cloud resources. With Terraform, you can describe your complete infrastructure architecture in code, enabling version control and repeatable deployments.

    Install via the official repository (EL 9 / EL 10)
    # Install the DNF plugin that provides config-manager
    sudo dnf install -y dnf-plugins-core
    # Add the HashiCorp official repository
    # Note: EL10 still uses DNF 4 (4.20), so `config-manager --add-repo` works the same as on EL9
    sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
    # Install Terraform
    sudo dnf install -y terraform
    # Verify installation
    terraform version
    Terminal window
    # Download the latest version (see https://developer.hashicorp.com/terraform/install for the current version)
    TERRAFORM_VERSION="1.9.0" # example version — replace with the latest from the official site
    wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip
    # Extract and install
    sudo dnf install -y unzip
    unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip
    sudo mv terraform /usr/local/bin/
    sudo chmod +x /usr/local/bin/terraform
    # Verify
    terraform version
    Terminal window
    # Install auto-completion
    terraform -install-autocomplete
    # Reload the shell
    source ~/.bashrc

    Terraform configuration files use the .tf extension and HCL syntax.

    # Comments start with #
    # Block structure
    resource "type" "name" {
    param1 = "value1"
    param2 = 123
    # Nested block
    nested_block {
    key = "value"
    }
    }
    # String interpolation
    variable "name" {
    default = "myserver"
    }
    resource "example" "demo" {
    name = "prefix-${var.name}"
    }
    # String
    name = "web-server"
    # Number
    count = 3
    # Boolean
    enabled = true
    # List
    availability_zones = ["cn-hangzhou-a", "cn-hangzhou-b"]
    # Map
    tags = {
    Name = "web-server"
    Environment = "production"
    Team = "ops"
    }

    Providers are plugins that allow Terraform to interact with cloud platforms.

    providers.tf
    terraform {
    required_version = ">= 1.5.0"
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 5.0"
    }
    }
    }
    provider "aws" {
    region = "ap-northeast-1" # Tokyo region
    access_key = var.aws_access_key
    secret_key = var.aws_secret_key
    # Or use environment variables (recommended):
    # export AWS_ACCESS_KEY_ID="your-access-key"
    # export AWS_SECRET_ACCESS_KEY="your-secret-key"
    }
    providers.tf
    terraform {
    required_version = ">= 1.5.0"
    required_providers {
    alicloud = {
    source = "aliyun/alicloud"
    version = "~> 1.220"
    }
    }
    }
    provider "alicloud" {
    region = "cn-hangzhou"
    access_key = var.alicloud_access_key
    secret_key = var.alicloud_secret_key
    }
    # variables.tf - Variable definitions
    variable "aws_access_key" {
    description = "AWS Access Key"
    type = string
    sensitive = true
    }
    variable "aws_secret_key" {
    description = "AWS Secret Key"
    type = string
    sensitive = true
    }
    variable "instance_type" {
    description = "EC2 instance type"
    type = string
    default = "t3.micro"
    }
    variable "instance_count" {
    description = "Number of instances"
    type = number
    default = 1
    }
    # main.tf - Main configuration file
    # Query the latest AlmaLinux 9 AMI
    data "aws_ami" "almalinux9" {
    most_recent = true
    owners = ["764336703387"] # AlmaLinux official
    filter {
    name = "name"
    values = ["AlmaLinux OS 9*x86_64*"]
    }
    filter {
    name = "virtualization-type"
    values = ["hvm"]
    }
    }
    # Create a security group
    resource "aws_security_group" "web" {
    name = "web-sg"
    description = "Allow HTTP and SSH"
    ingress {
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "SSH"
    }
    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"
    }
    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }
    tags = {
    Name = "web-security-group"
    }
    }
    # Create EC2 instances
    resource "aws_instance" "web" {
    count = var.instance_count
    ami = data.aws_ami.almalinux9.id
    instance_type = var.instance_type
    vpc_security_group_ids = [aws_security_group.web.id]
    user_data = <<-EOF
    #!/bin/bash
    dnf install -y nginx
    systemctl enable --now nginx
    echo "<h1>Server ${count.index + 1}</h1>" > /usr/share/nginx/html/index.html
    EOF
    tags = {
    Name = "web-server-${count.index + 1}"
    Env = "production"
    }
    }
    # outputs.tf - Output definitions
    output "instance_public_ips" {
    description = "List of instance public IPs"
    value = aws_instance.web[*].public_ip
    }
    output "instance_ids" {
    description = "List of instance IDs"
    value = aws_instance.web[*].id
    }
    output "ami_id" {
    description = "AMI ID used"
    value = data.aws_ami.almalinux9.id
    }
    # main.tf - Alibaba Cloud ECS example
    variable "alicloud_access_key" {
    type = string
    sensitive = true
    }
    variable "alicloud_secret_key" {
    type = string
    sensitive = true
    }
    # Query available zones
    data "alicloud_zones" "default" {
    available_resource_creation = "VSwitch"
    }
    # Query images
    data "alicloud_images" "almalinux" {
    name_regex = "^almalinux_9"
    most_recent = true
    owners = "system"
    }
    # Create a VPC
    resource "alicloud_vpc" "main" {
    vpc_name = "tf-demo-vpc"
    cidr_block = "172.16.0.0/16"
    }
    # Create a VSwitch
    resource "alicloud_vswitch" "main" {
    vswitch_name = "tf-demo-vsw"
    vpc_id = alicloud_vpc.main.id
    cidr_block = "172.16.1.0/24"
    zone_id = data.alicloud_zones.default.zones[0].id
    }
    # Create a security group
    resource "alicloud_security_group" "web" {
    name = "tf-demo-sg"
    vpc_id = alicloud_vpc.main.id
    }
    resource "alicloud_security_group_rule" "allow_ssh" {
    type = "ingress"
    ip_protocol = "tcp"
    port_range = "22/22"
    security_group_id = alicloud_security_group.web.id
    cidr_ip = "0.0.0.0/0"
    }
    resource "alicloud_security_group_rule" "allow_http" {
    type = "ingress"
    ip_protocol = "tcp"
    port_range = "80/80"
    security_group_id = alicloud_security_group.web.id
    cidr_ip = "0.0.0.0/0"
    }
    # Create an ECS instance
    resource "alicloud_instance" "web" {
    instance_name = "tf-demo-ecs"
    image_id = data.alicloud_images.almalinux.images[0].id
    instance_type = "ecs.t6-c1m1.large"
    security_groups = [alicloud_security_group.web.id]
    vswitch_id = alicloud_vswitch.main.id
    internet_max_bandwidth_out = 10
    system_disk_size = 40
    user_data = base64encode(<<-EOF
    #!/bin/bash
    dnf install -y nginx
    systemctl enable --now nginx
    EOF
    )
    tags = {
    Name = "web-server"
    Env = "demo"
    }
    }
    output "public_ip" {
    value = alicloud_instance.web.public_ip
    }
    Terminal window
    # Enter the project directory
    cd /opt/terraform/myproject
    # Initialize (downloads Provider plugins)
    terraform init
    # Upgrade Provider versions
    terraform init -upgrade
    Terminal window
    # View the plan (preview changes that will be made)
    terraform plan
    # Save the plan to a file
    terraform plan -out=tfplan
    # Use a variable file
    terraform plan -var-file="production.tfvars"
    # Pass a single variable
    terraform plan -var="instance_count=3"
    Terminal window
    # Apply changes (requires confirmation)
    terraform apply
    # Use a saved plan file (no confirmation needed)
    terraform apply tfplan
    # Auto-approve (for CI/CD)
    terraform apply -auto-approve
    # Use a variable file
    terraform apply -var-file="production.tfvars"
    Terminal window
    # Destroy all resources
    terraform destroy
    # Auto-approve destruction
    terraform destroy -auto-approve
    # Destroy only a specific resource
    terraform destroy -target=aws_instance.web
    Terminal window
    # Format configuration files
    terraform fmt
    # Recursively format
    terraform fmt -recursive
    # Validate configuration syntax
    terraform validate
    # View current state
    terraform show
    # List all resources
    terraform state list
    # View details for a specific resource
    terraform state show aws_instance.web[0]
    # Refresh state (sync with actual remote state)
    terraform refresh
    # Generate a dependency graph
    terraform graph | dot -Tpng > graph.png

    Use .tfvars files to manage variables for different environments:

    production.tfvars
    instance_type = "t3.large"
    instance_count = 3
    staging.tfvars
    instance_type = "t3.micro"
    instance_count = 1
    Terminal window
    # Use different environment variables
    terraform apply -var-file="production.tfvars"
    terraform apply -var-file="staging.tfvars"

    Pass sensitive information via environment variables:

    Terminal window
    # Terraform automatically reads environment variables with the TF_VAR_ prefix
    export TF_VAR_aws_access_key="AKIAIOSFODNN7EXAMPLE"
    export TF_VAR_aws_secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
    terraform apply

    The Terraform state file (terraform.tfstate) records the current state of the infrastructure. For team collaboration, a remote backend should be used to store the state file.

    Terminal window
    # State file is located in the project directory
    ls -la terraform.tfstate
    ls -la terraform.tfstate.backup
    terraform {
    backend "s3" {
    bucket = "my-terraform-state"
    key = "production/terraform.tfstate"
    region = "ap-northeast-1"
    encrypt = true
    dynamodb_table = "terraform-lock" # State locking
    }
    }
    terraform {
    backend "oss" {
    bucket = "my-terraform-state"
    prefix = "production"
    region = "cn-hangzhou"
    encrypt = true
    tablestore_endpoint = "https://tf-state-lock.cn-hangzhou.ots.aliyuncs.com"
    tablestore_table = "terraform-lock"
    }
    }
    Terminal window
    # List resources in the state
    terraform state list
    # View resource details
    terraform state show aws_instance.web[0]
    # Move a resource (rename)
    terraform state mv aws_instance.web aws_instance.webserver
    # Remove a resource from state (without deleting the actual resource)
    terraform state rm aws_instance.web[0]
    # Import an existing resource into Terraform management
    terraform import aws_instance.web i-0abc123def456
    # Pull remote state
    terraform state pull > state.json
    # Push state to remote
    terraform state push state.json

    Modules are used to encapsulate and reuse Terraform configurations.

    Terminal window
    # Module directory structure
    mkdir -p modules/ecs-instance
    modules/ecs-instance/variables.tf
    variable "instance_name" {
    description = "Instance name"
    type = string
    }
    variable "instance_type" {
    description = "Instance specification"
    type = string
    default = "ecs.t6-c1m1.large"
    }
    variable "image_id" {
    description = "Image ID"
    type = string
    }
    variable "vswitch_id" {
    description = "VSwitch ID"
    type = string
    }
    variable "security_group_id" {
    description = "Security group ID"
    type = string
    }
    variable "tags" {
    description = "Resource tags"
    type = map(string)
    default = {}
    }
    modules/ecs-instance/main.tf
    resource "alicloud_instance" "this" {
    instance_name = var.instance_name
    instance_type = var.instance_type
    image_id = var.image_id
    vswitch_id = var.vswitch_id
    security_groups = [var.security_group_id]
    internet_max_bandwidth_out = 10
    system_disk_size = 40
    tags = var.tags
    }
    modules/ecs-instance/outputs.tf
    output "instance_id" {
    value = alicloud_instance.this.id
    }
    output "public_ip" {
    value = alicloud_instance.this.public_ip
    }
    output "private_ip" {
    value = alicloud_instance.this.private_ip
    }
    # main.tf - Using a custom module
    module "web_server" {
    source = "./modules/ecs-instance"
    instance_name = "web-server-01"
    instance_type = "ecs.t6-c1m1.large"
    image_id = data.alicloud_images.almalinux.images[0].id
    vswitch_id = alicloud_vswitch.main.id
    security_group_id = alicloud_security_group.web.id
    tags = {
    Role = "web"
    Env = "production"
    }
    }
    module "api_server" {
    source = "./modules/ecs-instance"
    instance_name = "api-server-01"
    instance_type = "ecs.c6.large"
    image_id = data.alicloud_images.almalinux.images[0].id
    vswitch_id = alicloud_vswitch.main.id
    security_group_id = alicloud_security_group.web.id
    tags = {
    Role = "api"
    Env = "production"
    }
    }
    output "web_server_ip" {
    value = module.web_server.public_ip
    }
    output "api_server_ip" {
    value = module.api_server.public_ip
    }
    # Using a module from the Terraform Registry
    module "vpc" {
    source = "alibaba/vpc/alicloud"
    version = "1.10.0"
    vpc_name = "production-vpc"
    vpc_cidr = "10.0.0.0/8"
    }
    terraform-project/
    ├── environments/
    │ ├── production/
    │ │ ├── main.tf
    │ │ ├── variables.tf
    │ │ ├── outputs.tf
    │ │ ├── terraform.tfvars
    │ │ └── backend.tf
    │ └── staging/
    │ ├── main.tf
    │ ├── variables.tf
    │ ├── outputs.tf
    │ ├── terraform.tfvars
    │ └── backend.tf
    ├── modules/
    │ ├── ecs-instance/
    │ ├── vpc/
    │ └── security-group/
    └── .gitignore

    Create a .gitignore for your Terraform project:

    Terminal window
    cat > .gitignore << 'EOF'
    # Terraform
    .terraform/
    *.tfstate
    *.tfstate.backup
    *.tfplan
    *.tfvars
    !example.tfvars
    # Sensitive files
    *.pem
    *.key
    EOF

    Terraform is the core tool for Infrastructure as Code, bringing cloud resource creation and management under version control. Combined with Cloud-Init for passing user-data and Ansible for subsequent configuration, these three tools together form a complete automated infrastructure delivery pipeline.