Background

最進流行 Infrastructure as Code 的概念,Terraform 則是其中一個比較知名的工具,他的核心目標是 Write, Plan, and create Infrastructure as Code。 那這篇文章就稍微介紹一下 Infrastructure as Code 的好處和來寫第一個 Terraform 的 config 檔。

Introduction

Terraform 的好處可以用程式的概念來管理多層次的資源。從上層的軟體配置到底層的網絡、系統配置都可以使用 Terraform 統一進行管理。(可能工程師還是喜歡用 cli 而不是用 web 介面吧XD)

加上這幾年火紅和相對成熟的 Devops 生態系,兩者如果可以有效的結合看起來是一個不錯的系統管理模式。那當然因為把他變成code了所以可以進行版本控管,這也是另一個蠻重要的好處。

Creating your first Terraform infrastructure on AWS

Setup AWS Account

首先要先設定一組 AWS account 給 Terraform 使用。那因為我們希望利用 Terraform 來管理多層次的資源,所以我們直接給 admin 的權限。(請小心使用)

Screen-Shot-2019-08-29-at-5.41.30-PM

Screen-Shot-2019-08-29-at-5.41.44-PM

Start

instance.tf

# Configure credential AWS Provider
provider "aws" {
  region     = "ap-northeast-1"
  access_key = ""
  secret_key = ""
}

resource "aws_instance" "example" {
  ami                    = "ami-0eeb679d57500a06c"
  instance_type          = "t2.micro"
}

首先我們要先建立 instance.tf,在 instance.tf 中你要選擇你想使用的 provider, 官網中有列表可以參考。每個 provider 有各自的 secret_key 要填入,這篇文章我們使用的是AWS,所以我們填入剛剛創建帳號的 access_key & secret_key。

接著我們要選擇我們要使用 provider 中的哪一個 resoure,重上面連結的列表點進去你想要的 provider 即可看到所有相關的 resoure。這邊我們要建立一台 instance 所以選擇 aws_instance 這個 resoure。

example 則是這個 resource 的變數名,如果在之後的程式中有需要用到這個 resoure 的話呼叫 example 即可。

完成後我們接著執行下面的指令

$ terraform init

Initializing the backend...

Initializing provider plugins...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 2.22"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
$ terraform plan

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                          = "ami-0eeb679d57500a06c"
      + arn                          = (known after apply)
      + associate_public_ip_address  = (known after apply)
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
      + key_name                     = (known after apply)
      + network_interface_id         = (known after apply)
      + password_data                = (known after apply)
      + placement_group              = (known after apply)
      + primary_network_interface_id = (known after apply)
      + private_dns                  = (known after apply)
      + private_ip                   = (known after apply)
      + public_dns                   = (known after apply)
      + public_ip                    = (known after apply)
      + security_groups              = (known after apply)
      + source_dest_check            = true
      + subnet_id                    = (known after apply)
      + tenancy                      = (known after apply)
      + volume_tags                  = (known after apply)
      + vpc_security_group_ids       = (known after apply)

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + snapshot_id           = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + iops                  = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

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

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

分別解釋這兩個指令, terraform init 是初始化整個專案,他會去根據 instance.tf 的內容去下載所以相關的 package。terraform plan 則是可以讓你在執行之前觀察 Terraform 將做哪些改變,看是否跟我們預期的結果相同。

確定都沒問題之後我們下 terraform apply 的指令

$ terraform apply
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.example: Creating...
aws_instance.example: Still creating... [10s elapsed]
aws_instance.example: Still creating... [20s elapsed]
aws_instance.example: Creation complete after 25s [id=i-039a44596cedb1a7f]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

都沒問題話回到AWS EC2 Console 可以看到多了一台 t2.micro 的機器。

那如果你要關掉的話則是下 terraform destroy 這個指令

$ aws_instance.example: Destroying... [id=i-039a44596cedb1a7f]
aws_instance.example: Still destroying... [id=i-039a44596cedb1a7f, 10s elapsed]
aws_instance.example: Still destroying... [id=i-039a44596cedb1a7f, 20s elapsed]
aws_instance.example: Destruction complete after 21s

Destroy complete! Resources: 1 destroyed. destroy
Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes
aws_instance.example: Destroying... [id=i-039a44596cedb1a7f]
aws_instance.example: Still destroying... [id=i-039a44596cedb1a7f, 10s elapsed]
aws_instance.example: Still destroying... [id=i-039a44596cedb1a7f, 20s elapsed]
aws_instance.example: Destruction complete after 21s

Destroy complete! Resources: 1 destroyed.

以上就是 Terraform 最基本的應用。

Reference