[OCI] Terraform を 使って Block Volume バックアップのリストアとマウント (2018/12/25)

コードを使用してインフラストラクチャのトポロジを定義するHashicorp社の[Terraform](https://www.terraform.io/)を使って[Oracle Cloud Infrastructure](https://cloud.oracle.com/ja_JP/iaas)でInfrastructure as Code（IaC）を実現することができます。

この記事では、Terraformを使ってOCI Block Volumeのバックアップをリストアし、にLinuxインスタンスからマウントしてみたことを紹介します。

# 今回構築する構成
![image02.jpg](https://qiita-image-store.s3.amazonaws.com/0/108635/698b64dd-6110-5294-5f49-589d707fd708.jpeg)

事前にOracle LinuxのVMインスタンスにマウントされているBlock Volumeのバックアップを取得しておき、準備していたVCN/Subnetに新規にOracle LinuxのVMインスタンスを作成し、バックアップしていたBlock Volumeをリストアし、マウントする構成を以下のファイルから作成します。

| ファイル名 | 内容 |
|:-:|:-:|
|data_sources.tf|作成したリソース情報の取得|
|instance.tf|Computeインスタンスの作成|
|provider.tf|Terraform OCI Provider設定|
|variables.tf|変数・値の定義|
|volume.tf|バックアップから新規Block Volumeの作成|
|volume_attach.tf|Block Volumeのアタッチ・iSCSI接続・ファイスシステムのマウント|
（すべてのファイルは本ページの最下部にまとめて記載/env-vars.ps1を除く）

# 準備作業
環境を構築をする上で、使用する環境の情報および作成するインスタンスへの接続に必要な情報を準備します。
準備に必要な情報は
「[Oracle Cloud Advent Calendar 2018](https://adventar.org/calendars/3077)」の12月10日の記事
「[Terraform を 使って Oracle Cloud環境構築 (2018/12/10)](https://qiita.com/kenwatan/items/eda524e7db08a7010a66)」などを参照してください。

以下のOCIDを取得して、variables.tfに記入
・Block Volume バックアップのOCIDを取得
![image03.jpg](https://qiita-image-store.s3.amazonaws.com/0/108635/c3037194-ccf8-006b-0bba-172a6beeee84.jpeg)

・VMインスタンスを作成するサブネットのOCIDを取得

# インスタンス の作成
変数の追加(Linux VM/VM.Standard2.1 シェイプ を作成）

```variables.tf
variable "NumInstances" {
  default = "2"
}
variable "instance_image_ocid" {
  type = "map"

  default = {
    // See https://docs.us-phoenix-1.oraclecloud.com/images/
    // Oracle-provided image "Oracle-Linux-7.5-2018.05.09-1"
    us-ashburn-1 = "ocid1.image.oc1.iad.aaaaaaaa6ybn2lkqp2ejhijhehf5i65spqh3igt53iyvncyjmo7uhm5235ca"
  }
}

variable "instance_shape" {
  default = "VM.Standard2.1"
}
```

「`NumInstances`」で作成するインスタンスの数を指定します。
そのほか作成するインスタンスのシェイプ、イメージを指定します。

```instance.tf
resource "oci_core_instance" "TF_instance" {
  count               = "${var.NumInstances}"
  availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "TF instances${count.index}"
  hostname_label      = "TFinstance${count.index}"
  shape               = "${var.instance_shape}"
  subnet_id           = "${var.TF_SubnetOCID}"

  metadata {
    ssh_authorized_keys = "${var.ssh_public_key}"
  }

  source_details {
    source_type = "image"
    source_id   = "${var.instance_image_ocid[var.region]}"
  }

  timeouts {
    create = "60m"
  }

}
```

# Blcok Volumeのリストア
##### 変数の追加
リストアするBlock Volume BackupのOCIDを指定します。

```variables.tf
variable "volume_backup_ocid" {
  default = "ocid1.volumebackup.oc1.iad.abuwcljtdmtyzcgzeu3pvhhch3sqvsxpqvuomul2fw5hoscqivhbaie5mera"
}
```

##### リストアしてBlock Volume の作成

```volume.tf
resource "oci_core_volume" "datavolume" {
  count               = "${var.NumInstances}"
  availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "attact-tf-volume${count.index}"
  source_details {
    #Required
#    id = "${data.oci_core_volume_backups.test_volume_backups.id}"
    id = "${var.volume_backup_ocid}"
    type                   = "volumeBackup"
  }
}
```

# Blcok Volumeのアタッチ、iSCSI接続、ファイルシステムのマウント
##### Mount Targetの作成

```volume_attach.tf
resource "oci_core_volume_attachment" "backup_volume_attachments" {
  depends_on = ["oci_core_instance.TF_instance",
  "oci_core_volume.datavolume",
  ]
  count           = "${var.NumInstances}"
  attachment_type = "iscsi"
  compartment_id  = "${var.compartment_ocid}"
  instance_id     = "${oci_core_instance.TF_instance.*.id[count.index]}"
  volume_id       = "${oci_core_volume.datavolume.*.id[count.index]}"

    connection {
      agent       = false
      timeout     = "15m"
      host        = "${oci_core_instance.TF_instance.*.public_ip[count.index % var.NumInstances]}"
      user        = "opc"
      private_key = "${var.ssh_private_key}"
    }

  # register and connect the iSCSI block volume
  provisioner "remote-exec" {
    inline = [
      "sudo iscsiadm -m node -o new -T ${self.iqn} -p ${self.ipv4}:${self.port}",
      "sudo iscsiadm -m node -o update -T ${self.iqn} -n node.startup -v automatic",
      "sudo iscsiadm -m node -T ${self.iqn} -p ${self.ipv4}:${self.port} -l",
    ]
  }

  # initialize partition and file system
  provisioner "remote-exec" {
    inline = [
      "sudo systemctl start ocid.service",
      "set -x",
      "export DEVICE_ID=ip-${self.ipv4}:${self.port}-iscsi-${self.iqn}-lun-1",
      "sudo mkdir -p /mnt/vol01",
      "export UUID=$(sudo /usr/sbin/blkid -s UUID -o value /dev/sdb1)",
      "echo 'UUID='$${UUID}' /mnt/vol01 xfs defaults,_netdev,nofail 0 2' | sudo tee -a /etc/fstab",
      "sudo mount -a",
    ]
  }
}
```

# 環境構築の実行
#### すべてのファイルが用意できたら以下のコマンドを実行し環境を作成します。

- terraform init
- terraform plan -out plan01
- terraform apply "plan01"



# 作成されたインスタンスの確認

##### instance0 への接続
/dev/sdb1 が /mnt/vol01 にマウントされていることを確認

```
[root@tfinstance0 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        7.2G     0  7.2G   0% /dev
tmpfs           7.3G     0  7.3G   0% /dev/shm
tmpfs           7.3G  8.6M  7.3G   1% /run
tmpfs           7.3G     0  7.3G   0% /sys/fs/cgroup
/dev/sda3        39G  1.8G   37G   5% /
/dev/sda1       512M  9.8M  502M   2% /boot/efi
tmpfs           1.5G     0  1.5G   0% /run/user/1000
/dev/sdb1        50G   33M   50G   1% /mnt/vol01```
```

# おわりに
terraform を使って OCI Block Volumeのバックアップをリストアし、にLinuxインスタンスからマウントできることを確認しました。

以下のファイルはgithubからも確認できます。
https://github.com/kenwatan/terraform_BlockVolumeRestoreMount

```data_sources.tf
# Gets a list of Availability Domains
data "oci_identity_availability_domains" "ADs" {
  compartment_id = "${var.tenancy_ocid}"
}

```

```instance.tf
resource "oci_core_instance" "TF_instance" {
  count               = "${var.NumInstances}"
  availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "TF instances${count.index}"
  hostname_label      = "TFinstance${count.index}"
  shape               = "${var.instance_shape}"
  subnet_id           = "${var.TF_SubnetOCID}"

  metadata {
    ssh_authorized_keys = "${var.ssh_public_key}"
  }

  source_details {
    source_type = "image"
    source_id   = "${var.instance_image_ocid[var.region]}"
  }

  timeouts {
    create = "60m"
  }

}
```


```provider.tf
provider "oci" {
  version          = ">= 3.0.0"
  tenancy_ocid     = "${var.tenancy_ocid}"
  user_ocid        = "${var.user_ocid}"
  fingerprint      = "${var.fingerprint}"
  private_key_path = "${var.private_key_path}"
  region           = "${var.region}"
}
```

```variables.tf
variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "region" {}

variable "compartment_ocid" {}

# Refer https://docs.us-phoenix-1.oraclecloud.com/Content/Compute/Tasks/managingkeypairs.htm on how to setup SSH key pairs for compute instances
variable "ssh_public_key" {}

variable "ssh_private_key" {}

variable "api_public_key" {
  default = "-----BEGIN PUBLIC KEY-----aaaaaaaaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+1qg64wel39kHkppz4Fv2vaLXF9qIeDjeo3G4sHQIDAQAB-----END PUBLIC KEY-----"
}

variable "NumInstances" {
  default = "1"
}

variable "instance_shape" {
  default = "VM.Standard2.1"
}
# Choose an Availability Domain
variable "availability_domain" {
  default = "2"
}

variable "TF_SubnetOCID" {
  default = "ocid1.subnet.oc1.iad.aaaaaaaaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

variable "instance_image_ocid" {
  type = "map"

  default = {
    // See https://docs.us-phoenix-1.oraclecloud.com/images/
    // Oracle-provided image "Oracle-Linux-7.5-2018.05.09-1"
    eu-frankfurt-1 = "ocid1.image.oc1.eu-frankfurt-1.aaaaaaaazregkysspxnktw35k4r5vzwurxk6myu44umqthjeakbkvxvxdlkq"

    us-ashburn-1 = "ocid1.image.oc1.iad.aaaaaaaa6ybn2lkqp2ejhijhehf5i65spqh3igt53iyvncyjmo7uhm5235ca"
    uk-london-1  = "ocid1.image.oc1.uk-london-1.aaaaaaaayodsld656eh5stds5mo4hrmwuhk2ugin4eyfpgoiiskqfxll6a4a"
    us-phoenix-1 = "ocid1.image.oc1.phx.aaaaaaaaozjbzisykoybkppaiwviyfzusjzokq7jzwxi7nvwdiopk7ligoia"
  }
}

variable "volume_backup_ocid" {
  default = "ocid1.volumebackup.oc1.iad.aaaaaaaaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

```volume.tf
resource "oci_core_volume" "datavolume" {
  count               = "${var.NumInstances}"
  availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "attact-tf-volume${count.index}"
  source_details {
    #Required
#    id = "${data.oci_core_volume_backups.test_volume_backups.id}"
    id = "${var.volume_backup_ocid}"
    type                   = "volumeBackup"
  }
}
```

```volume_attach.tf
resource "oci_core_volume_attachment" "backup_volume_attachments" {
  depends_on = ["oci_core_instance.TF_instance",
  "oci_core_volume.datavolume",
  ]
  count           = "${var.NumInstances}"
  attachment_type = "iscsi"
  compartment_id  = "${var.compartment_ocid}"
  instance_id     = "${oci_core_instance.TF_instance.*.id[count.index]}"
  volume_id       = "${oci_core_volume.datavolume.*.id[count.index]}"

    connection {
      agent       = false
      timeout     = "15m"
      host        = "${oci_core_instance.TF_instance.*.public_ip[count.index % var.NumInstances]}"
      user        = "opc"
      private_key = "${var.ssh_private_key}"
    }

  # register and connect the iSCSI block volume
  provisioner "remote-exec" {
    inline = [
      "sudo iscsiadm -m node -o new -T ${self.iqn} -p ${self.ipv4}:${self.port}",
      "sudo iscsiadm -m node -o update -T ${self.iqn} -n node.startup -v automatic",
      "sudo iscsiadm -m node -T ${self.iqn} -p ${self.ipv4}:${self.port} -l",
    ]
  }

  # initialize partition and file system
  provisioner "remote-exec" {
    inline = [
      "sudo systemctl start ocid.service",
      "set -x",
      "export DEVICE_ID=ip-${self.ipv4}:${self.port}-iscsi-${self.iqn}-lun-1",
      "sudo mkdir -p /mnt/vol01",
      "export UUID=$(sudo /usr/sbin/blkid -s UUID -o value /dev/sdb1)",
      "echo 'UUID='$${UUID}' /mnt/vol01 xfs defaults,_netdev,nofail 0 2' | sudo tee -a /etc/fstab",
      "sudo mount -a",
    ]
  }

  # unmount and disconnect on destroy
  provisioner "remote-exec" {
    when       = "destroy"
    on_failure = "continue"

    inline = [
      "set -x",
      "export DEVICE_ID=ip-${self.ipv4}:${self.port}-iscsi-${self.iqn}-lun-1",
      "export UUID=$(sudo /usr/sbin/blkid -s UUID -o value /dev/sdb1)",
      "sudo umount /mnt/vol01",
      "if [[ $UUID ]] ; then",
      "  sudo sed -i.bak '\\@^UUID='$${UUID}'@d' /etc/fstab",
      "fi",
      "sudo iscsiadm -m node -T ${self.iqn} -p ${self.ipv4}:${self.port} -u",
      "sudo iscsiadm -m node -o delete -T ${self.iqn} -p ${self.ipv4}:${self.port}",
    ]
  }

}
```