Terraform学習
次
なんか試せるプロバイダでリソース一つつくるワンパス
チュートリアルや公式に目を通してみるtarraform languageは軽く抑えた
terraform consoleよりも試しやすい手段の確保 null_resourceで
ゴリゴリ書いて試してみる(tf文法を使いこなす)
github providerで実オブジェクトCRUD混みで色々試してみる
↓ すっげー見づらいからそろそろまとめよう
再利用性高くする
でもなー、何でも入りのこのpjに入れるのはなぁ
Q: 将来、他言語のoutput vars扱い始めたらどうするのん?
そのとき考えればいいです
Q: このPJ、割と他者(特にエンジニアでない一般層や知的生産者層)から読んでもらうこと想定してるつもりだけど、Terraformみたいな技術ゴリゴリのネタ入れても誰もわからんやん 何を今さら
GitHubで試してる
プライベートなので僕しか見れないけどpublicにした
外部ファイルとして readme をコミットしてみるところ
Branch main not found in repository or repository is not readable
sta.icon*3コイツが手強すぎる
長かったー
https://gyazo.com/82f90f9567003b99aa367fe9e7f4fd22
1
事前
create instance で、AWS の場合は……、GCPの場合は…… ← こういうの全部対応してるんだよね?
もっといえばこの「create instance」みたいな共通命令がずらぁって揃ってんだよね?
AWS の XXXX が使いたい、みたいな PaaS 依存の命令を叩く手段はある?
手軽に試すにはどうしたらいい?
できればプライベートで PaaS 契約なしに無料で済ませたい
AWSの場合はどこまでAPIをサポートされているの?
たとえば今会社で使ってる程度は全部サポートしている?
AWS CloudFormation YAML to terraform format 可能?
AWS マネコンでスタックを操作する……みたいな GUI ベースだけど、terraform にはない?CLI完結?
インスタンス潜った後の作業はどうする?
いわゆるAnsibleのレイヤー
Terraformは構成ファイルで宣言した状態を取得し、変更内容を宛先のプロバイダーにプッシュ
TerraformはGo言語で書かれたAWS SDKを使用し
サンプル
main.tf で aws 使いますよと credential
resource.tf で ec2 と ebs
variables.tf で var.db_database_name みたいな、resource.tf から使う設定(変数定義)
実行
terraform init
npm install みたいなことしてる?
とすると node_modules みたいなフォルダができる?
terraform validate
まあ普通の validate
terraform plan
dry run?
terraform apply
dry run 後の実行?
terraform destroy
まあ普通のdelete
宣言的定義、が重要コンセプトか
宣言的に定義できる とは「t2.micro インスタンスを1つ」と書くだけで、作成手順を意識しなくてもその通りに出来上がるというこ
terraform show
apply でつくったオブジェクトの確認
2
HCL1かHCL2を見分ける簡単な方法は、単純な変数の参照に "${}" が必要かどうか
とりあえず色々便利になってるのはわかった
最初から賢いやり方、で行きたいのでなるべく見る
目次読んで
CloudFormation よりもプログラミングっぽく書ける機能が多そう
Terraform 自体のバージョンを管理する
Terraform のデバッグ(デバッグログなど)
基本用語
Configration …… tfファイルのこと
HCL …… tfファイルで採用してるDSL
Module …… 再利用可能にまとめられた Configuration の単位
Provider …… ResourceやData Sourceなどを作成/更新/削除するプラグイン
sta.iconわかりやすい!
terraform fmt
Golangみたくあるんだ、良い
インタラクティブに試す
この関数の挙動よく分からんなぁーってときは terraform console でインタラクティブなREPLが起動できるので、これで試すと便利
手動いじりの許容
リソース自体はTerraformで作るんだけど、運用の都合上、手動で設定いじっても無視して欲しい属性は lifecycle ブロックで ignore_changes に指定すると差分を無視できます。
構築時に使うパスワードの戦略
環境変数みたいに変数で渡すようにしても、Stateには記録されちゃうンゴ
ので、上記 lifecyfle を ignore_changes にしとく&初期パスワードで作成、その後本番のパスワードに変える、が良い
今のところif文はないんですが、三項演算子なら書けます。
三項演算子見づらいから嫌い
terraform自体のバージョン管理
tfenv
tfファイルに terraform.required_version 書くことで指定バージョン以外での実行を禁止できる
State
Stateの状態を記録した terraform.tfstate の理解は避けて通れません。tfstateを制すものがTerraformを制すと言っても過言ではないでしょう。
リファクタリング時はリソースを意識する
再生成可能なリソースであればこれでも構わないのですが、実際問題DBなど作り直しづらいリソースも存在します。こういう場合は terraform state mv コマンドを使います。
sta.iconなるほどなー、手元で変えさえすればいいってわけじゃなくて、作成中のリソースがどう作り直されるかも意識が必要ってことか
デバッグログ
TF_LOG=DEBUG を環境変数にセットするとデバッグログ
sta.iconああ、terraform 自体のデバッグログってことか
tfファイルにconsole.log書いて出す、ではなくて
なんかterraformをソースレベルで動かしてデバッグしてるんだが……
そこまではしたくないなぁ
3
正直これだけ読めばいいんだけど、英語なのでまずは軽いので底上げしておきたい
やっぱり先読んだ方がええわ
label はただの識別子でn個並べられるのかー、へーとか
plan file の解説もあるし
.tfplan
手を動かせる手段知りてえ
プロバイダ工夫したら行ける気がする
GitHubとか?
ここで一通り書き方身につけたい
シングルバイナリええやん
頑張れば入手とpath化までpowershellで自動化できる
With the previously mentioned execution plan and resource graph, you know exactly what Terraform will change and in what order, avoiding many possible human errors.
前述の実行計画とリソースグラフを使用することで、Terraformがどのような変更をどのような順序で行うかを正確に把握することができ、多くのヒューマンエラーを回避することができます。
planとresource graphつくっておけば、差分適用の成功率が上がると
Terraform console
Windows版 v0.14.3だと使いづらすぎる(カーソルキーさえ効かない、コピペも上手くいかない)
単一行expression以外は、別手段で試した方が良さそう
用語
https://gyazo.com/5b9568ee1b8b791e4630078477aedabd
block
blockをネストすることがある
argument
変数参照ができる
関数書ける
モジュール
single root module
そっから呼ばれる child modules
overideとマージ
argumentが被ったら上書きする
ルールなんか色々あるけど、レアらしいのでまずは「被ったら上書きされる」
syntax
block label
リソースによって何個指定するかが決まってる
0もある
identifier は [^0-9][a-zA-Z0-9_\-]*
comment
# が良い( // も使えるが慣例では使わんし fmt などは勝手に # に直す)
/* */
改行コード
CRLFも扱えるけど内部的にはLFデフォ
勝手にLFに変換するのもあるある
Style
色々あるけど fmt 使えば一発です
resource
resource "(resource-type)" "(local-name)"
resource-type はロードした provider 次第
local-name はこのリソースを参照するためのエイリアス
スコープはモジュール内
モジュール内ならどこからでも共有される
ドキュメント見ろ
Qiitaでもあったけど割と反映遅めっぽい(GitHubちょっと触った僕も早速そやったし
meta-argument
depends_on……terraformが自動解決しないリソース間の依存。インスタンスつくる前にIAMつくるとか
providers……module call時に、使うproviderを指定できる
count……リソースをn個つくる場合に指定。i番目を記述したければcount.indexを使う
for_each……for_each={……}の中身を一つずつ使ってリソースをn個つくる。each.keyやeach.valueを使う
集合しか受け付けないので渡す前にtoset()で変換してやる
state
xxx.tfでつくった"実際のリソース"を記録しておくもの
でないと Update や Destroy 時にどのリソース操作すればいいかわからん
resource "aws_instance" …… でインスタンスつくったとする
内部的には AWS の i-xxxxxxxxxxx みたいなインスタンスIDが出来上がる
これを記録しておかないと、後で更新や削除ができん
保存ファイル
.tfstate
保存先
デフォはローカル
複数人開発用にリモートにもできる
構造まで言及しているけど、いじる場面はやっぱりあるらしい……
わからなければ terraform consoleで試す
プリミティブは一通りある
map(objectとも)だけちょっとわかりづらい
code:map.tf
{
name = "john"
age = 52
}
:ではなく=であり、,や;もつけない
以下は必要に応じて自動変換
bool to string, string to bool, number to string, string to number
heredoc
code:heredoc.tf
<<EOT
hello
world
EOT
1 <<の後に目印を定義して改行
2 本文
3 目印でおしまい
慣習では EO 始まりで大文字
template string
Interpolation: jsにもある${var.NAME} とか
Directive: vue.jsのv-forやv-ifみたいなことが %{ ... } でできる
見づらいのでheredoc中で使え
reference
table:reference
resource <RESOURCE TYPE>.<NAME>
input var var.<NAME>
output var module.<MODULE NAME>.<OUTPUT NAME>
local var locals.<NAME>
data source data.<DATA TYPE>.<NAME>
Filesystem path.module, path.root, path.cwd
[for o in var.list : o.id] → var.list[*].id
operator
&& || !
余りは %
Python でいう *args みたいなやつは min([55, 2453, 2]...) ← リストと ...
返す結果(配列やオブジェクト)に sensitive data 含まれてたら、全体が sensitive になる
x {"a"="123",(sensitive)}
o (sensitive)
ビルトイン関数はこっち
yaml や json 変換、プリミティブの変換系、IPアドレス、ファイルパス、日付時刻
いわゆる三項演算子
condition ? true_val : false_val
true_valとfalse_valは同じ型である必要アリ
list返したいなら[]囲み、[for s in var.list : upper(s)]
obj返したいなら {} 囲みと KEY_EXPRESSION => VALUE_EXPRESSION、{for s in var.list : s => upper(s)}
Pythonの内包表記レベルは(ネスト以外は)できそう
[for o in var.list : o.id] を var.list[*].id と書けるやつ
var.list[*].interfaces[0].name は直感に反するが、
var.list[0].interfaces[0].name
var.list[1].interfaces[0].name
……
と list を返す
settings {……}を複数個指定できる
これをdynamicにつくりたい場合に、このdynamic blocksが使える
ベストプラクティス
基本的に使うな(愚直に指定しろ)
only when you need to hide details in order to build a clean user interface for a re-usable module
型の制約と type 式
ふうん
you specify a range of acceptable versions
version = ">= 1.2.0, < 2.0.0"
npmとほぼ同じ
=、!=、> >= < <=
~> は初耳だ
within a specific minor release, use the full version number
~> 1.0.4 will allow installation of 1.0.5 and 1.0.10 but not 1.1.0.
そのマイナーバージョンに限って >、ってことか
input var
モジュール内で使えるローカル変数的なもの
variable {……}で定義
値の注入が別途必要
実行時、コマンドライン引数、環境変数、変数ファイル
var.<NAME>でアクセス
output var
他モジュールから読んでもらうための export 的なもの
output {……}で定義
value=……で値を指定
module.<MODULE NAME>.<OUTPUT NAME>でアクセス
local var
繰り返し登場する値のエイリアスをつくる定数定義みたいなもの
locals {……}で定義
<AliasName>=<Expression>
locals.<NAME>でアクセス
requirements
ルートレベルは terraform{required_providers{……}}
nameに対するsourceやversionを定義する
モジュール内限定は provider{……}
使うproviderをnameで指定する
指定したname(にあたるsource)が存在しない場合
# If there is no source, terraform assumes that the host is "registry.terraform.io", the namespace is "hashicorp", and the type is the map key (random)
なので provider "github" {} だけだと hashicorp/github になる、とか
lockfile
package-lock.jsonみたいなやつで、厳密な依存関係を記述したやつ
.terraform.lock.hcl
giboで生成された分ではバージョン管理除外してない root と child
child とは root または child から呼ばれたやつ
使う
module As指定する名前{source="モジュールが存在するパス"}
パス(ソース)の指定方法は色々ある
./path/to ローカル
hashicorp/path/to Terraform Registry
github.com/path/to/ GitHubから
その他のargumentsは、モジュール側のinput varに指定するイメージ
meta-argumentsもいくつか使える
モジュール側でoutput varを定義しておけば、呼び出し元から参照可
あとから「モジュールでくくるか」とかすると、state変わっちゃうので注意
terraform state mv とか terraform taint とか tfstate 直編集とかで頑張る必要があるらしい まあまあ副作用でかいので thin wrapper 程度でばかすか使わない
明確に抽象度上げられるブツなどに
ベスプラ
main.tf, variables.tf, outputs.tf, readme.md
variablesとoutputは利用者に読んでもらうこと前提で簡潔コメントを
modules/
nested modules はこっちに
modules/moduleA も上記の最小構造を取る
examples/
これつくって例を示すと優しい
利用者が使えるように module path は remote の分で指定すること
「モジュールAとBを組み合わせてなんかしたい」場合
o 呼び出し元でAとBを使う
x AとBを使ったモジュールCをつくって、呼び出し元はCを使う
つまり再利用しやすいモジュールの部品を並べる、というアプローチ
sta.iconまあKISSだなとは思うが、まだピンと来ないな