クラウドの中の IaC。Terraformのインストールと最初のスクリプトの実行 (2021/03/01)

クラウドの中の IaC。Terraformのインストールと最初のスクリプトの実行 (2021/03/01)

https://blogs.oracle.com/developers/iac-in-the-cloud:-installing-terraform-and-running-your-first-script
投稿者:Todd Sharp

前回の記事では、開発者向けにTerraformの基本を紹介しました。
今回の記事では、Terraformをインストールして、Oracle Cloud Infrastructureテナントと対話するためのモジュールの作成を開始します。
この記事では、ローカルでTerraformを使用しているので、まず最初にTerraformをダウンロードしてインストールします。
Hashicorpのダウンロードページから適切なバイナリを探してインストールします。
インストールが完了したら、バージョン番号を確認してインストールをテストします。
このブログ記事が公開された日の時点で、これで以下のようになりました。

$ terraform -v
Terraform v0.14.5

OCI Terraform プロバイダ - インストールと認証


プロバイダを手動でダウンロードすることもできますが、Terraformにダウンロードさせた方が簡単です。
プロバイダブロックを設定している場合はそうなりますので、ここでは手動でのインストールは省きましょう。
プロバイダに移る前に、TerraformレジストリにあるOCI Terraform Providerのドキュメントをブックマークしておきましょう。

OCI Terraform Providerでの認証にはいくつかのオプションがありますが、ここではAPI Key Authenticationオプションを使用します。
このオプションを気に入っているのは、もしOCI CLIがローカルにインストールされていれば(完全にインストールされているはずです)、
CLIの設定ファイルを読むだけで必要な情報をすべて取得できるからです。

CLIがない?問題ありません。必要な情報がどこにあるかについては、ドキュメントを参照してください。

ここに収集する必要のある情報があります。

  • tenancy_ocid
  • user_ocid
  • private_key_path
  • private_key_password (オプション - 秘密鍵がパスワードで保護されている場合)
  • fingerprint
  • region

こんな感じでローカルマシンから入手しました。


これらの値をTerraformに取り込む簡単な方法は、TF_VAR_をプレフィックスとする環境変数として設定することです。
この特別な接頭辞により、スクリプト内で利用できるようになりますので、OSによっては、環境変数が設定されていることを確認してから実行してください。
例えば、私のMacでは、.zshrcファイルの中に変数を設定して、ターミナルからいつでも利用できるようにしています。
また、必要に応じて bash スクリプトを作成してソースを取ることもできます。 設定する必要がある変数は以下の通りです。

export TF_VAR_tenancy_ocid=<tenancy_OCID>
export TF_VAR_compartment_ocid=<compartment_OCID>
export TF_VAR_user_ocid=<user_OCID>
export TF_VAR_fingerprint=<key_fingerprint>
export TF_VAR_private_key_path=<private_key_path>
export TF_VAR_private_key_password=<private_key_password>
export TF_VAR_region=<region>

エコーで設定されていることを確認します。

これで、最初の .tf ファイルを作成することができます。
空のディレクトリに移動して provider.tf というファイルを作成し、お好みの IDE で開きます。

trsharp at ora-recursivecodes-mb in /projects/terraform
$ cd /projects/terraform
$ mkdir my-first-tf && cd my-first-tf
$ touch provider.tf
$ code .

provider.tfを入力して保存します。

provider "oci" {
tenancy_ocid = var.tenancy_ocid
user_ocid = var.user_ocid
private_key_path = var.private_key_path
private_key_password = var.private_key_password
fingerprint = var.fingerprint
region = var.region
}

次に、同じディレクトリに variables.tf というファイルを作成します。
このファイルを使って、プロジェクト内の変数を宣言します。
環境変数で設定した変数は、プロジェクトのどこかに対応する宣言がないとアクセスできないので、設定した変数はすべてTF_VARとして宣言してください。

variable "compartment_ocid" {}
variable "tenancy_ocid" {}
variable "user_ocid " {}
variable "private_key_path" {}
variable "private_key_password" {}
variable "fingerprint" {}
variable "region" {}

IDEで新しいターミナル(またはOSのターミナル)を開き、terraform initを実行してください。
初めて実行すると、TerraformはOCI Terraformプロバイダを使用していることに気付き、自動的にダウンロードしてくれます。
出力は以下のようになります。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/oci...
- Installing hashicorp/oci v4.11.0...
- Installed hashicorp/oci v4.11.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

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実行計画の作成と適用


Terraform CLIにはいくつかのコマンドがありますが、
最もよく使うのはplan、application、destroyの3つです(destroyはこの3つの中では最も使用頻度が低いと思われます)。
開発中、consoleは式を評価したり実験したりするのに便利な手段です(console docs)。

プランって何?スタン?

planコマンドは、希望する状態と現在の状態を比較して、現在の状態から希望する状態への実行計画を生成します。
これは実際には何もしません - 計画を作成するだけです。
一般的には、スクリプトを検証し、計画が実行したいことを実行するかどうかを確認するために計画を実行します。
実際には、今すぐ実行してください。

$ terraform plan

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

そうですね、リソースが定義されていないので、計画には何もありません(まだ)!
同じディレクトリで variables.tf を開いて、bucket_namespace という変数を定義して、
Object Storage の名前空間と同じ値を設定してみましょう。

[success]

自分の名前空間とは?簡単にわかるようになっています。

[/success]

variable "bucket_namespace" {
default = "toddrsharp"
}

変数が設定されているかどうか、ざっと見てみましょう。

$ terraform console
> var.bucket_namespace
"toddrsharp"

素晴らしい!期待通りです。
ターミナルを終了して、別の新しいファイルを作成しましょう。これを test.tf と呼びます。

あーあ、行き詰った。Terraformコンソールでヘルプを入力してください。
exit と入力して終了するか、CTRL+D または CTRL+C を使用してください。

オブジェクト・ストレージ・データ・ソースを使用して、
テナント内のすべてのオブジェクト・ストレージ・バケットをリストアップしてみましょう。
test.tfで、次のように追加します。

data "oci_objectstorage_bucket_summaries" "bucket_summaries" {
compartment_id = var.compartment_ocid
namespace = var.bucket_namespace
}

さて、コンソールでこのデータソースの値を確認してください。
前回の記事で覚えているように、データソースの出力にはデータの前にデータを付け、次に操作タイプとローカルラベルを付けなければなりません。

$ terraform console
> data.oci_objectstorage_bucket_summaries.bucket_summaries
(known after apply)

あー、まだこの情報は掴めないんだ。
データを手に入れるには、プランを適用しなければならない。

どうやって適用するんだ?


確かに印象的なプランではないが、それでもプランなので、適用してみよう。
でもその前に、バケツのサマリーを印刷するための出力ブロックを追加しましょう。

output "bucket_summaries" {
value = data.oci_objectstorage_bucket_summaries.bucket_summaries
}

このプランを適用すると(terraform applyで)、テナント/名前空間内の各バケットのバケットサマリーオブジェクトのリストが表示されます。
Terraformのsplat構文を使ってバケット名のリストを集めて、もう少し読みやすくしてみましょう。

output "bucket_summaries" {
value = data.oci_objectstorage_bucket_summaries.bucket_summaries.bucket_summaries[*].name
}

もう一度適用を実行すると、今度はより読みやすい出力が得られます。

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

Outputs:

bucket_summaries = tolist([
"archive-demo",
"barn-captures",
"custom-images",
"doggos",
"insulin-helper-uploads",
"micronaut-lab-assets",
"object-upload-demo-public",
"oss-storage-bucket",
"readme-assets",
"rocket-chat-uploads",
"usage_reports",
"wallet",
])

これまでのところ、実際のリソース作成はまだ行っていません - 基本的な変数の宣言、プロバイダの設定、データソースの読み込みと出力だけです。
新しいバケットを作成して結果を出力するリソースブロックを test.tf に追加して、リソースの作成に取り掛かりましょう。
また、バケットのサマリーを一覧表示するためのデータソースの呼び出しは不要なので削除します。

resource "oci_objectstorage_bucket" "create_bucket" {
# required
compartment_id = var.compartment_ocid
name = "my_new_bucket"
namespace = var.bucket_namespace

# optional
access_type = "ObjectRead"
}

output "new_bucket" {
value = oci_objectstorage_bucket.create_bucket
}

terraform planを実行すると、生成されたプランが表示されます。

$ terraform plan

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:

# oci_objectstorage_bucket.create_bucket will be created
+ resource "oci_objectstorage_bucket" "create_bucket" {
+ access_type = "ObjectRead"
+ approximate_count = (known after apply)
+ approximate_size = (known after apply)
+ bucket_id = (known after apply)
+ compartment_id = "ocid1.compartment.oc1..[redacted]"
+ created_by = (known after apply)
+ defined_tags = (known after apply)
+ etag = (known after apply)
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ is_read_only = (known after apply)
+ kms_key_id = (known after apply)
+ name = "my_new_bucket"
+ namespace = "toddrsharp"
+ object_events_enabled = (known after apply)
+ object_lifecycle_policy_etag = (known after apply)
+ replication_enabled = (known after apply)
+ storage_tier = (known after apply)
+ time_created = (known after apply)
+ versioning = (known after apply)
}

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

Changes to Outputs:
- bucket_summaries = [
- "archive-demo",
- "barn-captures",
- "custom-images",
- "doggos",
- "insulin-helper-uploads",
- "micronaut-lab-assets",
- "object-upload-demo-public",
- "oss-storage-bucket",
- "readme-assets",
- "rocket-chat-uploads",
- "usage_reports",
- "wallet",
] -> null
+ new_bucket = {
+ access_type = "ObjectRead"
+ approximate_count = (known after apply)
+ approximate_size = (known after apply)
+ bucket_id = (known after apply)
+ compartment_id = "ocid1.compartment.oc1..[redacted]"
+ created_by = (known after apply)
+ defined_tags = (known after apply)
+ etag = (known after apply)
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ is_read_only = (known after apply)
+ kms_key_id = (known after apply)
+ metadata = null
+ name = "my_new_bucket"
+ namespace = "toddrsharp"
+ object_events_enabled = (known after apply)
+ object_lifecycle_policy_etag = (known after apply)
+ replication_enabled = (known after apply)
+ retention_rules = []
+ storage_tier = (known after apply)
+ time_created = (known after apply)
+ timeouts = null
+ versioning = (known after apply)
}

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

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.

これは予想通りですね~
バケットのまとめリストを削除して、新たにバケットを作成して結果を出力する計画をレイアウトしています。
しかし、最後の注意点を確認してください。out パラメータを指定することで、計画をディスクに保存することができます。

$ terraform plan -out test

[removed for brevity]

This plan was saved to: test

To perform exactly these actions, run the following command to apply:
terraform apply "test"

ということで、計画は保存されていたのですね~読んでみましょう。



うーん、どうやら2進法のようだから、読めないのは仕方ないです。
しかし、この保存された計画を適用することはできます。

$ terraform apply test
oci_objectstorage_bucket.create_bucket: Creating...
oci_objectstorage_bucket.create_bucket: Creation complete after 1s [id=n/toddrsharp/b/my_new_bucket]

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

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the <code class="code-inline">terraform show</code> command.

State path: terraform.tfstate

Outputs:

new_bucket = {
"access_type" = "ObjectRead"
"approximate_count" = "0"
"approximate_size" = "0"
"bucket_id" = "ocid1.bucket.oc1.[redacted]"
"compartment_id" = "ocid1.compartment.oc1..[redacted]"
"created_by" = "ocid1.user.oc1..[redacted]"
"defined_tags" = tomap({
"Oracle-Tags.CreatedBy" = ""
"Oracle-Tags.CreatedOn" = "2021-02-02T14:00:30.661Z"
})
"etag" = "b92e2a05-8d63-466b-afe3-0932605f0ce7"
"freeform_tags" = tomap({})
"id" = "n/toddrsharp/b/my_new_bucket"
"is_read_only" = false
"kms_key_id" = tostring(null)
"metadata" = tomap(null) /* of string */
"name" = "my_new_bucket"
"namespace" = "toddrsharp"
"object_events_enabled" = false
"object_lifecycle_policy_etag" = tostring(null)
"replication_enabled" = false
"retention_rules" = toset([])
"storage_tier" = "Standard"
"time_created" = "2021-02-02 14:00:30.676 +0000 UTC"
"timeouts" = null /* object */
"versioning" = "Disabled"
}

素晴らしい!
バケットが作成されたようです。OCI CLIで確認してみましょう。

$ oci os bucket get --bucket-name my_new_bucket --region us-phoenix-1
\ > | jq '.data | {name: .name, createdOn: ."time-created"}’
{
"name": "my_new_bucket",
"createdOn": "2021-02-02T14:00:30.676000+00:00"
}

OCIコンソールでも確認できます。



あ、待って!
誤ってこの新しいバケットをパブリックバケットにしてしまいました。
プライベートに変更する必要があります。Terraformスクリプトに戻り、プロパティを更新して、適用ジョブを再実行します。

resource "oci_objectstorage_bucket" "create_bucket" {
# required
compartment_id = var.compartment_ocid
name = "my_new_bucket"
namespace = var.bucket_namespace

# optional
access_type = "NoPublicAccess" # <---- updated
}

再度実行してみると、Terraformは状態(バケットが存在する)を知っているので、
新しいバケットを作成するのではなく、バケットを更新することを決定していることに気づきます。
また、アクセスタイプの変更を指摘し、何をするかを教えてくれます。

$ terraform apply
oci_objectstorage_bucket.create_bucket: Refreshing state... [id=n/toddrsharp/b/my_new_bucket]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

# oci_objectstorage_bucket.create_bucket will be updated in-place
~ resource "oci_objectstorage_bucket" "create_bucket" {
~ access_type = "ObjectRead" -> "NoPublicAccess"
id = "n/toddrsharp/b/my_new_bucket"
name = "my_new_bucket"
# (16 unchanged attributes hidden)
}

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

Changes to Outputs:
~ new_bucket = {
~ access_type = "ObjectRead" -> "NoPublicAccess"
# (22 unchanged elements hidden)
}

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

oci_objectstorage_bucket.create_bucket: Modifying... [id=n/toddrsharp/b/my_new_bucket]
oci_objectstorage_bucket.create_bucket: Modifications complete after 3s [id=n/toddrsharp/b/my_new_bucket]

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

コンソールで変更が適用されたことを確認します。



破棄するにはどうすればいいですか?


何らかの理由でTerraformプロジェクトで作成されたインフラをすべて削除したい場合は、terraform destroyを実行することができます。

$ terraform destroy

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

Terraform will perform the following actions:

# oci_objectstorage_bucket.create_bucket will be destroyed
- resource "oci_objectstorage_bucket" "create_bucket" {
- access_type = "NoPublicAccess" -> null
- approximate_count = "0" -> null
- approximate_size = "0" -> null
- bucket_id = "ocid1.bucket.oc1.[redacted]" -> null
- compartment_id = "ocid1.compartment.oc1..[redacted]" -> null
- created_by = "ocid1.user.oc1..[redacted]" -> null
- defined_tags = {
} -> null
- etag = "ac1ae994-7a46-4709-bf22-28e78fc28a62" -> null
- freeform_tags = {} -> null
- id = "n/toddrsharp/b/my_new_bucket" -> null
- is_read_only = false -> null
- metadata = {} -> null
- name = "my_new_bucket" -> null
- namespace = "toddrsharp" -> null
- object_events_enabled = false -> null
- replication_enabled = false -> null
- storage_tier = "Standard" -> null
- time_created = "2021-02-02 14:00:30.676 +0000 UTC" -> null
- versioning = "Disabled" -> null
}

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

Changes to Outputs:
- new_bucket = {
- access_type = "NoPublicAccess"
- approximate_count = "0"
- approximate_size = "0"
- bucket_id = "ocid1.bucket.oc1.[redacted]"
- compartment_id = "ocid1.compartment.oc1..[redacted]"
- created_by = "ocid1.user.oc1..[redacted]"
- defined_tags = {
}
- etag = "ac1ae994-7a46-4709-bf22-28e78fc28a62"
- freeform_tags = {}
- id = "n/toddrsharp/b/my_new_bucket"
- is_read_only = false
- kms_key_id = null
- metadata = {}
- name = "my_new_bucket"
- namespace = "toddrsharp"
- object_events_enabled = false
- object_lifecycle_policy_etag = null
- replication_enabled = false
- retention_rules = []
- storage_tier = "Standard"
- time_created = "2021-02-02 14:00:30.676 +0000 UTC"
- timeouts = null
- versioning = "Disabled"
} -> null

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

oci_objectstorage_bucket.create_bucket: Destroying... [id=n/toddrsharp/b/my_new_bucket]
oci_objectstorage_bucket.create_bucket: Destruction complete after 3s

Destroy complete! Resources: 1 destroyed.

まとめ

この記事では、TerraformとTerraform OCI Providerをインストールし、
Oracle Cloudのインフラストラクチャを管理するための最初のTerraformスクリプトを作成、計画、適用しました。
OCI Providerは、Oracle Cloudのすべてのインフラストラクチャ要素を完全にサポートしていることに注意してください。
テナントで実行する必要がある操作の具体的な実装の詳細については、ドキュメントを参照してください。
次回の記事では、ローカルではなくOracle CloudでTerraformを使用する方法を紹介します。

Photo by Daniel Páscoa on Unsplash

コメント

このブログの人気の投稿

Oracle RACによるメンテナンスのためのドレインとアプリケーション・コンティニュイティの仕組み (2023/11/01)

Oracle Cloud Infrastructure Secure Desktopsを発表: デスクトップ仮想化のためのOracleのクラウドネイティブ・サービス (2023/06/28)

新しいOracle Container Engine for Kubernetesの機能強化により、大規模なKubernetesがさらに簡単になりました (2023/03/20)