Terraform初探:管理AWS Lightsail例項

夢哲發表於2021-11-23

Terraform是一種開源基礎設施及程式碼(IaC)的工具,可提供一致的CLI(命令列介面)工作流來管理數百個雲服務,將雲API編碼為宣告性的配置檔案進行管理。
本文建立一個管理AWS Lightsail例項的例子來入門Terraform的使用。

安裝Terraform CLI

要使用Terramform,首先要在本地系統安裝Terraform命令列工具。HashiCorp提供了預編譯好的二進位制分發包,可以通過(https://www.terraform.com/dow...) 直接下載相應平臺的二進位制包,解壓後放到相應的執行路徑。也可以通過一些軟體包管理工具安裝,例如在Linux/OS X上通過LinuxBrew/HomeBrew進行安裝,在Windows上通過Chocolatey進行安裝。

這裡我們示例在Linux上是使用LinuxBrew進行安裝

> brew install terraform

安裝完成後,可以檢視其版本

❯ terraform -version
Terraform v1.0.11
on linux_amd64

使用-help檢視其可用命令,安裝成功後,我們就可以使用Terraform來建立相應的基礎設施專案了。

AWS賬號準備

本文將通過建立一個管理AWS Lightsial例項的專案來嘗試Terraform,因此需要一個AWS賬號,以及在本地環境安裝和配置好AWS CLI工具的訪問憑據。
安裝和配置AWS CLI,請參考其文件 (https://docs.aws.amazon.com/c...) 。 配置完成之後,可以在本地命令列終端訪問相應的AWS資源。

建立並初始化Terraform專案

Terraform在本地通過資料夾來管理一個基礎設施專案的宣告性程式碼,例如我們在本地建立一個資料夾

> mkdir mylightsail
> cd mylightsail/

進入資料夾後,建立一個以 .tf 作為字尾的檔案,例如 main.tf

> touch main.tf

然後使用編輯器開啟檔案進行編輯,寫入以下程式碼塊

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.65"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "ap-southeast-1"
}

其中 terraform/required_providers 塊定義了該專案需要的 Provider,Terraform是通過不同的Provider來管理相應的基礎設施資源的,可到 (https://registry.terraform.io) 來查詢需要的Providers,例如GCP,Azure以及阿里雲等的Providers。這裡因為我們要管理的資源是AWS Lightsail例項,所以使用了Hashicorp官方提供的 hashicorp/aws

provider "aws" 部分配置了該Provider的一些可選項,例如這裡配置了區域為 ap-southeast-1 ,因此請確保上面配置的AWS訪問憑據能夠操作該區域的資源。

也就是這裡我們定義了我們需要使用的Provider及其相應的選項配置,接下來我們需要使用 terraform init 命令來初始化專案

> terraform init

Initializing provider plugins...
...
Terraform has been successfully initialized!

初始化將會從 (https://registry.terraform.io/) 下載相應的Provider外掛到 .terramorm/providers/ 目錄,供接下來的命令使用。
同時,會生成一個 .terraform.lock.hcl 的檔案來記錄使用的具體Provider版本,其功能類似於NPM的package-lock檔案,可將其提交到程式碼版本管理倉庫,其他協作的成員就可以保持使用相同的外掛版本。

建立基礎設施資源

完成專案的初始化之後,我們就可以編寫需要建立的資源宣告性配置,可以直接將相應的配置寫入 main.tf 檔案,也可以另外建立新的以 .tf 作為字尾的檔案,這裡我們建立一個新的名為 resources.tf 的檔案,並寫入我們需要的資源的定義

## LightSail Resources

resource "aws_lightsail_static_ip" "Example-sig-ip" {
  name = "Example-EIP"
}

resource "aws_lightsail_instance" "Example-sig" {
  name              = "Example-Sig"
  availability_zone = "ap-southeast-1c"
  blueprint_id      = "ubuntu_20_04"
  bundle_id         = "nano_2_0"
  key_pair_name     = "LightsailDefaultKeyPair"
  tags = {
    Example = ""
  }
}

resource "aws_lightsail_static_ip_attachment" "Example-sig-ip-attache" {
  static_ip_name = aws_lightsail_static_ip.Example-sig-ip.id
  instance_name  = aws_lightsail_instance.Example-sig.id
}

resource "aws_lightsail_instance_public_ports" "Example-sig-public-ports" {
  instance_name = aws_lightsail_instance.Example-sig.name

  port_info {
    protocol  = "tcp"
    from_port = 0
    to_port   = 65535
    cidrs = [
      "0.0.0.0/0"
    ]
  }
  port_info {
    protocol  = "udp"
    from_port = 0
    to_port   = 65535
    cidrs = [
      "0.0.0.0/0"
    ]
  }
}

定義資源的格式為 resource "[provider_resource _type]" "resource_name",第一個引數為相應Provider支援的資源型別名稱,第二個引數為自己定義的資源名稱(可用於其他資源引用)。例如,我們首先定義了一個Lightsail的靜態IP資源,其中引數 name 指定了AWS資源的名稱。

上面的定義中,我們宣告瞭以下資源

  • 一個Lightsail靜態IP地址
  • 一個Lightsail計算例項,並繫結名為 LightsailDefaultKeyPair 的SSH金鑰
  • 靜態IP地址和計算例項的繫結
  • 例項的開放的網路埠組(類似於AWS EC2例項的安全組定義)

儲存檔案之後,我們可以使用 terraform fmt 命令來格式化檔案格式,以及 terraform validate 來檢查是否有語法錯誤。

定義好我們想要的資源之後,我們先通過命令 terraform plan 命令來執行計劃,檢視具體的執行更改(plan不會實際操作相應的資源)

❯ terraform plan                    

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_lightsail_instance.Example-sig will be created
  + resource "aws_lightsail_instance" "Example-sig" {
      + arn                = (known after apply)
      + availability_zone  = "ap-southeast-1c"
      + blueprint_id       = "ubuntu_20_04"
      + bundle_id          = "nano_2_0"
      + cpu_count          = (known after apply)
      + created_at         = (known after apply)
      + id                 = (known after apply)
      + ipv6_address       = (known after apply)
      + ipv6_addresses     = (known after apply)
      + is_static_ip       = (known after apply)
      + key_pair_name      = "LightsailDefaultKeyPair"
      + name               = "Example-Sig"
      + private_ip_address = (known after apply)
      + public_ip_address  = (known after apply)
      + ram_size           = (known after apply)
      + tags               = {
          + "Example" = ""
        }
      + tags_all           = {
          + "Example" = (known after apply)
        }
      + username           = (known after apply)
    }

  # aws_lightsail_instance_public_ports.Example-sig-public-ports will be created
  + resource "aws_lightsail_instance_public_ports" "Example-sig-public-ports" {
      + id            = (known after apply)
      + instance_name = "Example-Sig"

      + port_info {
          + cidrs     = [
              + "0.0.0.0/0",
            ]
          + from_port = 0
          + protocol  = "tcp"
          + to_port   = 65535
        }
      + port_info {
          + cidrs     = [
              + "0.0.0.0/0",
            ]
          + from_port = 0
          + protocol  = "udp"
          + to_port   = 65535
        }
    }

  # aws_lightsail_static_ip.Example-sig-ip will be created
  + resource "aws_lightsail_static_ip" "Example-sig-ip" {
      + arn          = (known after apply)
      + id           = (known after apply)
      + ip_address   = (known after apply)
      + name         = "Example-EIP"
      + support_code = (known after apply)
    }

  # aws_lightsail_static_ip_attachment.Example-sig-ip-attache will be created
  + resource "aws_lightsail_static_ip_attachment" "Example-sig-ip-attache" {
      + id             = (known after apply)
      + instance_name  = (known after apply)
      + ip_address     = (known after apply)
      + static_ip_name = (known after apply)
    }

Plan: 4 to add, 0 to change, 0 to destroy.

+表示將要增加的資源,(know after apply)的意思是要在具體只想(apply)之後,AWS根據定義建立相應資源之後才會返回的具體值。接下來就可以使用 terraform apply 來具體執行操作了,執行成功之後,會生成 .terraform/terraform.state 檔案來記錄執行後的資源狀態,也可以通過命令 terraform show 命令來檢視

❯ terraform show
# aws_lightsail_instance.Example-sig:
resource "aws_lightsail_instance" "Example-sig" {
    arn                = "arn:aws:lightsail:ap-southeast-1:090767794770:Instance/21cb0ea5-e814-4307-8606-01348d98be15"
    availability_zone  = "ap-southeast-1c"
    blueprint_id       = "ubuntu_20_04"
    bundle_id          = "nano_2_0"
    cpu_count          = 1
    created_at         = "2021-11-08T05:49:05Z"
    id                 = "Example-Sig"
    ipv6_address       = "2406:da18:8ae:4b02:1f2:4ff1:daa1:6a8c"
    ipv6_addresses     = [
        "2406:da18:8ae:4b02:1f2:4ff1:daa1:6a8c",
    ]
    is_static_ip       = true
    key_pair_name      = "LightsailDefaultKeyPair"
    name               = "Example-Sig"
    private_ip_address = "172.26.45.249"
    public_ip_address  = "54.220.33.133"
    ram_size           = 0.5
    tags               = {
        "Example" = ""
    }
    tags_all           = {
        "Example" = ""
    }
    username           = "ubuntu"
}

# aws_lightsail_instance_public_ports.Example-sig-public-ports:
resource "aws_lightsail_instance_public_ports" "Example-sig-public-ports" {
    id            = "Example-Sig-987241840"
    instance_name = "Example-Sig"

    port_info {
        cidrs     = [
            "0.0.0.0/0",
        ]
        from_port = 0
        protocol  = "tcp"
        to_port   = 65535
    }
    port_info {
        cidrs     = [
            "0.0.0.0/0",
        ]
        from_port = 0
        protocol  = "udp"
        to_port   = 65535
    }
}

# aws_lightsail_static_ip.Example-sig-ip:
resource "aws_lightsail_static_ip" "Example-sig-ip" {
    arn          = "arn:aws:lightsail:ap-southeast-1:090767794770:StaticIp/3f0298e0-efeb-4429-9574-156fef12a48f"
    id           = "Example-EIP"
    ip_address   = "54.220.33.133"
    name         = "Example-EIP"
    support_code = "313963776615/54.220.33.133"
}

# aws_lightsail_static_ip_attachment.Example-sig-ip-attache:
resource "aws_lightsail_static_ip_attachment" "exmaple-sig-ip-attache" {
    id             = "Example-EIP"
    instance_name  = "Example-Sig"
    ip_address     = "54.220.33.133"
    static_ip_name = "Example-EIP"
}

之後我們就可以通過更新資源定義檔案,然後執行 plan & apply 來更新雲上的資源了,如果資源不需要了,我們也可以通過 terraform destroy 一條命令來銷燬所有資源。

總結

本文以管理簡單的AWS Lightsail資源為例,展示瞭如何使用Terraform來管理雲上的資源。通過一宣告性的程式碼來定義我們需要的資源,同時資源定義程式碼可以通過版本管理工具進行版本化管理,進一步實現IaC的工作方式。

這麼我們使用的是Terraform的本地執行模式,除了在本地執行之外,Terraform還提供了執行後端(Backend)的功能,就可以將執行放到雲上的一些執行環境,資源狀態的管理也將會維護在Backend端,方便實現CI/CD Pipeline,以及GitOps的方式。其中Hashicorp的Terraform Cloud就是一個Backend。下一篇文章將示例將該專案放到Terraform Cloud上去執行。

【同時釋出在 Terraform初探:管理AWS Lightsail例項

相關文章