Terraformとは
-
IaCを実現するツール
-
インフラの初期プロビジョニング、更新、破棄をコード管理できる
-
メリット
- バージョン管理ができる
- 他者との共有、再利用ができる
- 構成をスムーズに変更できる
- 他のプロバイダへの移行がしやすい
初期準備
Terraformのインストール (macOSの場合です。適宜各環境にあった方法でインストールしてください)
-
brew install tfenv
- Terraformのバージョンに追随するためにもtfenvを使うのがおすすめです。
-
tfenv list-remote
- 現在利用可能なTerraformのバージョンを列挙します
-
tfenv install x.xx.x
- リストから対象のバージョンを選択します。
-
tfenv use x.xx.x
- インストールしたものの中で使うTerraformのversionを指定します。
providerの準備
- プロパイダーとは
- AWSやGoogleCloudなどのプラットフォームやソフトウェア、ハードウェアのAPIと対話するためのプラグイン。
- 変更したい対象のものを指定する。
- AWSやGoogleCloudなどのプラットフォームやソフトウェア、ハードウェアのAPIと対話するためのプラグイン。
- どんなプロバイダーがあるかは下記を参照してください
今回は使用ケースの多い、AWSを中心に説明していきます。
AWSの場合
AWSでの変更を行うために、予め認証情報を取得しておく必要があるので、先に対応を済ませておきます。
IAMユーザーの作成
下記、公式を参考にIAMユーザーを作成します。
権限は適宜必要なものに絞ってください。
シークレットキーが漏れると大変なことになります。
慎重に操作してください。
AWS CLIの設定
まだaws cliを取得していない方は下記コマンドでインストールします。
brew install awscli
続いて、Terraformでawsを使用するためのprofileを設定します。
YOUR_PROFILE_NAMEは何でもいいです。わかりやすい名前にしましょう。
今回はtestとします。(後半のtfファイルでprofile = test と指定しています。)
$ aws configure --profile YOUR_PROFILE_NAME
AWS Access Key ID[None]: IAMで作成したアクセスキーID
AWS Secret Access Key[None]: IAMで作成したシークレットアクセスキー
Default region name[None]: ap-northeast-1
Default output format[None]: json
# 下記のコマンドで接続ができるか確認してください。
$ aws sts get-caller-identity --profile YOUR_PROFILE_NAME
# Terraformで使用するAWS_PROFILEを環境変数に設定
$ export AWS_PROFILE=YOUR_PROFILE_NAME
Terraform構築
これで、すぐにでもTerraformを使っていく準備は整いました。
ですが、適当にリソースを作っていくと、管理が複雑になってしまうので、
管理がしやすくなるディレクトリ構成について、紹介しながら、Terraformの使い方を説明していきます。
ディレクトリ構成について
例
- service (例: サービス毎にディレクトリを区切る)
- backend.tf (Terraformのstate管理用)
- outputs.tf (他のディレクトリや他のリポジトリで現ディレクトリのリソース設定を使いたい場合に定義する)
- provider.tf (どこのプロバイダーを指定するか。 awsやgcpなど)
- remote_state.tf (他のディレクトリやリポジトリのTerraformのstate情報を取得する)
- variables.tf (変数を定義。全体で共通して使うものなど。)
- xxx.tf (s3やecsなどAWSのサービス毎にファイルを区切る)
-
backend.tfに記載されたstateの保存先と見比べて、記載のコードとの変化を見る
-
terraform plan
時にでてくる変更点はstateで保持されている内容とコードの差分
-
-
上記ファイルの準備ができたら
terraform init
を実行する(初回だけ)- ワークスペースを初期化するコマンドで、aws providerなどのダウンロード処理が走る
ファイルの記述方法
backend.tf
terraform {
backend "s3" {
bucket = "terraform-state-bucket"
key = "terraform.state.test"
region = "ap-northeast-1"
profile = "test"
}
}
Terraformではリソースを作成や変更したときに、stateというインフラの状態を管理しているファイルを作成します。
そのstateファイルは、個人で使う分にはローカルに保存しておいても問題ないのですが、複数人で使用する場合、
共有フォルダを作成してどこかで管理する必要が出てきます。
その共有フォルダの指定を行うために、このbackendというものがあリます。
今回はawsのs3で管理するので、s3のバケット名を指定し、keyに保存するファイル名を指定しています。
outputs.tf
output "alb_dns" {
value = aws_alb.alb.dns_name
}
別のプロジェクトなどで使う値を定義するために使います。詳しくはこちらの記事がおすすめです。
output ""
の名前はなんでもよい。外部で取得するときの名前になる。わかりやすい名前にするのがいい 。
valueに入るのは通常のリソースの指定と同じで、対象リソースを指定する(詳しくはxxx.tfで後述) 。
上の例はawsのalbでの例。
provider.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.65"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "ap-northeast-1"
profile = "test"
}
provider "aws" {
alias = "virginia"
region = "us-east-1"
profile = "test"
}
provider ""
required_providersで指定した対象のプロバイダーを指定する。
regionやprofileを変えたい場合はブロックの中にaliasを使うことで、他のファイルでも変更できる。
各リソースの設定でproviderの指定がない場合はデフォルトの設定が適用される。
provider = aws.virginia
といった形で各リソースで宣言することで適用される。
remote_state.tf
data "terraform_remote_state" "hogehoge" {
backend = "s3"
config = {
bucket = "terraform-state-bucket"
key = "terraform.state.test"
region = "ap-northeast-1"
profile = "test"
}
}
- 外部から参照したいstateを取得する
- s3でstate管理している場合はs3のバケットを指定すればOK
variables.tf
locals {
project_name = "hoge"
}
共通して使いたい変数を定義。下記のような形で他のファイルで呼び出し可能
local.project_name
xxx.tf(サービス毎のファイル)
- Terraformの公式ドキュメントを参照するのが良い。
以下はvpcの例。
この場合はファイル名をvpc.tfとして作る
resource "aws_vpc" "example" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc" "example"
最初のaws_vpcは決められた値。利用するサービス毎に固定。後ろのexampleはリソースの定義名。好きに決めて良いです。
ブロックの中身は利用するサービス毎に異なるので、公式ドキュメントを参考にしつつ記載すればOK
terraformコマンド
よく使うもの
-
terraform plan
実行前に、記載したコードでどんな変更があるかを確認できる -
terraform apply
コードで記載したものを実際に反映する -
terraform destroy
リソースを削除します。
使うと便利なもの
-
terraform fmt
コードの自動整形をしてくれる -
terraform import
すでに作られているもの(AWSコンソール上等で)をコード管理できる
その他、全容についてはterraform -h
で確認してください。
その他tips
- どのリソースに対しても付けられるオプションに、lifecycleというのがあります。
- リソースの変更時に特定の挙動を指定できるオプション。
- 例えば
prevent_destroy
をつけておくと、消すときにエラーが出るようになるので、誤った操作が起きないように、とりあえずつけておくと安心です。 - 詳しくは公式ドキュメントを参照してください!lifecycleについて
lifecycle {
prevent_destroy = true
}