terraformでAzure(その2 vm構築+α)

以前の記事はこちら

https://qiita.com/masa3521/items/70a464e270710ee2ae54

# 実施内容
-Virtual Machineと付随するリソースを構築する。
-変数を利用してみる。
-諸事情によりterraformバージョン(0.12.9)が変更が必要になったため、tfenvで管理する
-terraform.tfstateの保存先をAzure Storage Accountに変更

#tfenvとは

terraformのバージョン管理ソフトになります。
詳細は下記参照

https://github.com/tfutils/tfenv

#tfenvで管理(terraformのuninstall〜tfenvのインストールとterrafromのインストール)

```
% brew uninstall terraform
Uninstalling /usr/local/Cellar/terraform/0.12.18... (6 files, 50.9MB)

% brew install tfenv

==> Downloading https://github.com/tfutils/tfenv/archive/v1.0.2.tar.gz
==> Downloading from https://codeload.github.com/tfutils/tfenv/tar.gz/v1.0.2
#=#=#
🍺  /usr/local/Cellar/tfenv/1.0.2: 20 files, 29.2KB, built in 4 seconds

% tfenv install 0.12.9
[INFO] Installing Terraform v0.12.9
[INFO] Downloading release tarball from https://releases.hashicorp.com/terraform/0.12.9/terraform_0.12.9_darwin_amd64.zip
######################################################################################################################################################################################################################################################### 100.0%
[INFO] Downloading SHA hash file from https://releases.hashicorp.com/terraform/0.12.9/terraform_0.12.9_SHA256SUMS
tfenv: tfenv-install: [WARN] No keybase install found, skipping OpenPGP signature verification
Archive:  tfenv_download.aQegFa/terraform_0.12.9_darwin_amd64.zip
  inflating: /usr/local/Cellar/tfenv/1.0.2/versions/0.12.9/terraform
[INFO] Installation of terraform v0.12.9 successful
[INFO] Switching to v0.12.9
[INFO] Switching completed
masaakihamada@masaakinoMacBook-Pro tf-test %
masaakihamada@masaakinoMacBook-Pro tf-test %
masaakihamada@masaakinoMacBook-Pro tf-test %
masaakihamada@masaakinoMacBook-Pro tf-test % terraform --version
Terraform v0.12.9
+ provider.azurerm v1.39.0
```

#tfstateとは

実リソースの状態が記載しているファイルになります。
デフォルトではローカルに保存されて、リモートで保存することも可能です。
基本的にはチームで作業すると思うのでリモート(Azure Storage Account)で保存することにします。

>This state is stored by default in a local file named "terraform.tfstate", but it can also be stored remotely, which >works better in a team environment.

>Terraform uses this local state to create plans and make changes to your infrastructure. Prior to any operation, >Terraform does a refresh to update the state with the real infrastructure.

#tfstateをリモート管理する事前準備

下記が必要です
- Azure Storage Accountの作成
- アクセスキーを環境変数に設定

■Azure Storage Accountの作成

```bash:create_storageaccount.sh
#!/bin/bash

RESOURCE_GROUP_NAME=tstate
STORAGE_ACCOUNT_NAME=tstate$RANDOM
CONTAINER_NAME=tstate

# Create resource group
az group create --name $RESOURCE_GROUP_NAME --location japaneast

# Create storage account
az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob

# Get storage account key
ACCOUNT_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query [0].value -o tsv)

# Create blob container
az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME --account-key $ACCOUNT_KEY

echo "storage_account_name: $STORAGE_ACCOUNT_NAME"
echo "container_name: $CONTAINER_NAME"
echo "access_key: $ACCOUNT_KEY"
```

実行結果

```
~~~~省略~~~~~~
storage_account_name: tstate12763
container_name: tstate
access_key: **********************************
```

■アクセスキーを環境変数に設定

```
% export ARM_ACCESS_KEY="**********************************"
% env | grep ARM_ACCESS_KEY
ARM_ACCESS_KEY=**********************************
```

毎回読み込む必要があるならば.bashrc等に設定してください。

# 定義ファイル(backend.tf)
tfstateをリモートで管理するconfigになります。

```backend.tf
terraform {
  backend "azurerm" {
    resource_group_name  = "tstate"
    storage_account_name = "tstate12763"
    container_name       = "tstate"
    key                  = "terraform.tfstate"
  }
}
```


# 定義ファイル(vars.tf)

変数を宣言configになります。
defalut値が基本的に利用されるが、terraform planやterrform apply時にオプションで
指定することも可能。

```vars.tf
variable "resource_prefix" {
  default = "testprefix"
}

variable "location" {
  default = "japaneast"
}
```

# 定義ファイル(main.tf)

今回作成するファイルは下記

-Resource group
-Virtual network
-Subnet
-Network security group
-Network interface
-Virtual Machine

```main.tf
provider "azurerm" {
    version = "=1.39.0"
}

# Create a resource group
resource "azurerm_resource_group" "rg" {
    name     = "myTFResourceGroup"
    location = "japaneast"
}

# Create a virtual network
resource "azurerm_virtual_network" "vnet" {
    name                = "myTFVnet"
    address_space       = ["10.0.0.0/16"]
    location            = var.location
    resource_group_name = azurerm_resource_group.rg.name
}

# Create subnet
resource "azurerm_subnet" "subnet" {
  name                 = "myTFSubnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefix       = "10.0.1.0/24"
}

# Create public IP
resource "azurerm_public_ip" "publicip" {
  name                = "${var.resource_prefix}TFPublicIP"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method   = "Static"
}

# Create Network Security Group and rule
resource "azurerm_network_security_group" "nsg" {
  name                = "myTFNSG"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name

  security_rule {
    name                       = "SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

# Create network interface
resource "azurerm_network_interface" "nic" {
  name                      = "myNIC"
  location                  = var.location
  resource_group_name       = azurerm_resource_group.rg.name
  network_security_group_id = azurerm_network_security_group.nsg.id

  ip_configuration {
    name                          = "myNICConfg"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "dynamic"
    public_ip_address_id          = azurerm_public_ip.publicip.id
  }
}

# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {
  name                  = "myTFVM"
  location              = var.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.nic.id]
  vm_size               = "Standard_DS1_v2"

  storage_os_disk {
    name              = "myOsDisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Premium_LRS"
  }

  storage_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04.0-LTS"
    version   = "latest"
  }

  os_profile {
    computer_name  = "myTFVM"
    admin_username = "plankton"
    admin_password = "Password1234!"
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }
}
```

# 作成するリソースの確認〜作成

```
% terraform plan
Acquiring state lock. This may take a few moments...
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.

~~~省略~~~

Plan: 7 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 apply
Acquiring state lock. This may take a few moments...

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

~~~省略~~~

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

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    ※yesを入力しEnter

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

```

Apply complete!なれば完了です。

#作成したVMにログイン確認

IPアドレスの取得

```
% az vm list-ip-addresses --query "[].virtualMachine[].{Name:name, PublicIp:network.publicIpAddresses[0].ipAddress, PrivateIp:network.privateIpAddresses[0]}" -o table -g myTFResourceGroup
Name    PublicIp        PrivateIp
------  --------------  -----------
myTFVM  52.140.240.152  10.0.1.4
```

対象のホストにログイン

```
% ssh plankton@52.140.240.152
The authenticity of host '52.140.240.152 (52.140.240.152)' can't be established.
ECDSA key fingerprint is SHA256:AmCpQpiGo9TYY65wKZKHcNYMIPKGwxg2UZaxPCXEpsY.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '52.140.240.152' (ECDSA) to the list of known hosts.
plankton@52.140.240.152's password:
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.15.0-1066-azure x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

0 packages can be updated.
0 updates are security updates.



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

plankton@myTFVM:~$
```

お片付け

```
% terraform destroy


Plan: 0 to add, 0 to change, 7 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

Destroy complete! Resources: 7 destroyed.

% terraform show

% 


```

削除完了

#参考

[Terraform 公式ドキュメント](https://www.hashicorp.com/products/terraform/)
[Terraform get started](https://learn.hashicorp.com/terraform/?track=getting-started#getting-started)
[Terraform Azure Provider](https://www.terraform.io/docs/providers/azurerm/index.html)
[Terraform backend](https://www.terraform.io/docs/backends/types/azurerm.html)
[Azure Storage Account作成](https://docs.microsoft.com/en-us/azure/terraform/terraform-backend)
[Virtual MachineのIP取得](https://qiita.com/dz_/items/dda1a8f6198667406aeb)
[tfstateついて](https://www.terraform.io/docs/state/index.html)