Terraformで始めるInfrastructure as
Code
自己紹介
• 名前:岩本 貴久
• 所属:技術1課
• わさびちゃん →
はじめに
3
手作業は何故ダメ?
作成・変更履歴
作業ログ
ログを見ればわかる・・・?(作業者によって精度はまちまち)
再現性
作業ログ&手順書
怪しい
構成管理
毎回構成図の更新
その構成図、最新ですか?
4
Infrastructure as Code
Infrastructure as Code(IaC)とは?
インフラをコードで扱い、プログラムと同じ様にコードで管理・更新を行うこと
5
IaCのメリット
作成・変更履歴
Gitのコミットログ見ろ
再現性
コード実行しろ
構成管理
コード見ろ
6
IaCを運用する心構
IaCを本気でやる(運用する)心構
絶対にマネコンは触らない
ステートファイルを保持し続ける
デプロイのフロー
障害対応
最後までそのツールを使い続ける覚悟
7
IaCに必要なもの
8
IaCのツール
CloudFormation
Terraform ← 今日はこの話
Ansible
他・・・?
9
ここから、本題
10
Terraformとは?
HashiCorp(はしこーぷ)社がオープンソースで開発しているプロビジョニ
ング ツール
AWS以外に、GCP、Azure、OpenStack、Vmware、他、に対応
書式はDSL(domain-specific language/ドメイン固有言語)で記載
複数のプロバイダに同時にプロビジョニングも可能
11
Terraformの仕組み
12
AWS API
terraform plan terraform apply terraform destroy
main.tf
ローカル環境
terraform.tfstate
Terraformの範囲
Terraformはプロビジョナーと呼ばれる、各プラットフォーム向けアダプタ
が手供されている。
(AWSで言えば)AWS API がで構築できる範囲となる。
local-exec Provisioner
Terraformの実行環境でローカルコマンドを走らせることができる。
サンプル
13
provisioner "local-exec”{
command = "echo ${aws_instance.web.private_ip} >> private_ips.txt"
}
Terraformのインストール
Terraformのインストールは、バイナリファイルを任意のディレクトリに配
置するだけ。
MacならBrewでインストールが可能
14
Terraformを始める
1、ディレクトリを作成
2、「main.tf」ファイルを作成
15
$ mkdir sample-prj
$ cd sample-prj
$ touch main.tf
プロバイダーの設定(AWS)
「main.tf」内に以下の記載をする
プロジェクトの初期化
16
provider "aws" {
access_key = "ACCESS_KEY_HERE"
secret_key = "SECRET_KEY_HERE"
region = "ap-northeast-1"
}
$ terraform init
クレデンシャル、ベタ書き、ダメゼッタイ1
スタイリッシュなエンジニアはクレデンシャルも、ご安全に。
1、Terraform実行時の引数で指定する。
2、環境変数で値を渡す。
3、「 terraform.tfvars 」に記載する。
17
$ terraform apply 
-var 'access_key=XXXXXXXXXXXXXXXXXXXXXX’ 
-var 'secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$ export TF_VAR_access_key="AKIAXXXXXXXXXXXXXXXXXX"
$ export TF_VAR_secret_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
aws_access_key = "AKIAXXXXXXXXXXXXXXXXXX"
aws_secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
クレデンシャル、ベタ書き、ダメゼッタイ2
AssumeRoleが使えない
Profileを指定する。
Aswarp
https://github.com/fujiwara/aswrap
18
$ AWS_PROFILE=HOGE terraform xxxx
$ AWS_PROFILE=HOGE aswarp terraform xxxx
スタイリッシュな形
「main.tf」には、リージョンのみを記載する。
クレデンシャルは(AWS-CLIの)Profileで指定する。(←おすすめ)
Terraform実行時の引数で指定する。
環境変数で値を渡す。
「 terraform.tfvars 」に記載する。
19
provider "aws" {
region = "ap-northeast-1"
}
変数の利用
Terraform内では変数の利用が可能
「 terraform.tfvars 」
「 terraform.tfvars 」以外のファイルを指定する場合は、引数で指定する。
20
variable "foo" {}
resource "aws_s3_bucket" "s3_bucket" {
bucket = "${var.foo}”
}
foo = ”hoge-name"
リソースの設定(VPCを作る)
TerrafromでVPCを作るサンプルコード
21
resource "aws_vpc" "myVPC" {
cidr_block = "10.1.0.0/16"
instance_tenancy = "default"
enable_dns_support = "true"
enable_dns_hostnames = "false"
tags {
Name = "myVPC"
}
}
他のリソースを参照する
Terraform内で他のAWSリソースを参照する。
22
resource "aws_vpc" "myVPC" {
cidr_block = "10.1.0.0/16"
instance_tenancy = "default"
enable_dns_support = "true"
enable_dns_hostnames = "false"
tags {
Name = "myVPC"
}
}
resource "aws_internet_gateway" "myGW" {
vpc_id = "${aws_vpc.myVPC.id}" # myVPCのid属性を参照
}
テンプレートファイルを分割する
拡張子「.tf」ファイルに適当に分割する。
AWSサービス単位に分けるのがオススメ。
同一ディレクトリ内の「.tf」ファイルは実行時に読み込まれる。
「main.tf」 ファイルは必須。
23
リソースの依存関係
基本的にはTerraform側で依存関係を解決。
一部、作成のみを実行して作成完了を待たないリソースがある。
リソースの作成を待つには「depends_on」を用いる。
24
resource "aws_s3_bucket" "example" {
bucket = "terraform-getting-started-guide"
acl = "private"
}
resource "aws_instance" "example" {
ami = "ami-2757f631"
instance_type = "t2.micro"
depends_on = ["aws_s3_bucket.example"]
変数型の利用
Map型
List型
25
variable "images" {
type = "map"
default = {
us-east-1 = "image-1234"
us-west-2 = "image-4567"
}
}
variable "zones" {
default = ["us-east-1a", "us-east-1b"]
}
利用できる関数
https://www.terraform.io/docs/configuration/interpolation.html#built
-in-functions
例
file(path)
ローカルからファイルを読み込む。
join(delim, list)
文字列を結合する。
他
26
アウトプット
「Output」を用いて、作成されたリソースの値を出力
27
output "ip" {
value = "${aws_eip.ip.public_ip}"
}
Terraformの実行
ドライラン
適用/アップデート
環境の削除
28
$ terraform plan
$ terraform apply
$ terraform destroy
Terraformでの(インフラ)状態管理
ファイル「terraform.tfstate」
tfstateの中身はJSON
このファイルがコンフリクト、消失すると死ぬ
Gitで管理するのは非推奨
共有方法
Atlas
Consle
29
ちょっと先行くTerraformの使い方
30
ステイタス共有する
Terraformは管理対象のリソースを、ファイル「terraform.tfstate」で管理
する。
ディフォルトでは、カレントディレクトリに作成される。
S3 Backend
31
terraform {
backend "s3" {
bucket = "mybucket"
key = "path/to/my/key"
region = "us-east-1"
}
}
環境を切り替える(ワークスペース)
同じTerraformのコードをワークスペース(環境)ごとに使い分けることの
できる機能。
例えば、Production/developmentと2つのworkspaceを作成し、同じ
Terraformコードを利用して、2つの環境のリソースを作成できる。
32
Lambdaファンクションのデプロイ
33
data "archive_file" "sample_function" {
type = "zip"
source_dir = "lambda/sample_function"
output_path = "lambda/upload/sample_function.zip"
}
resource "aws_lambda_function" "sample_function" {
filename = "${data.archive_file.sample_function.output_path}"
function_name = "sample_function"
role = "${aws_iam_role.lambda_sample_function.arn}"
handler = "lambda_function.lambda_handler"
source_code_hash = "${data.archive_file.sample_function.output_base64sha256}"
runtime = "python3.6"
memory_size = 128
timeout = 30
}
同じEC2を複数台作成する
34
resource "aws_instance" "web" {
count = 2
ami = "ami-1234567"
instance_type = "t2.micro"
key_name = ”HOGE.key"
vpc_security_group_ids = [
"sg-987654",
]
subnet_id = "subnet-012345"
}
同じEC2を複数のリージョンに配置する
35
variable "subnets" {
default = {
"0" = "subnet-12345"
"1" = "subnet-56789"
}
}
resource "aws_instance" "web" {
count = 2
ami = "ami-12345"
instance_type = "t2.micro"
key_name = ”hoge.key"
vpc_security_group_ids = [
"sg-123456",
]
subnet_id = "${lookup(var.subnets, count.index%2)}"
}
異なるEC2を複数台作成する1
「main.tf」
36
variable "keypaer-name" {
}
variable "subnets" {
type = "list"
}
variable "ec2-param" {
type = "list"
}
異なるEC2を複数台作成する2
「terraform.tfvars」
37
subnets = [
{
subnet-cidr = "10.2.1.0/24"
subnet-az = "ap-northeast-1a"
},
{
subnet-cidr = "10.2.2.0/24"
subnet-az = "ap-northeast-1c"
}
]
ec2-param = [
{
ami-id = "ami-08847abae18baa040"
ec2-instance-type = "t2.micro"
ec2-volume-size = "20"
ec2-subnet = 1
}
]
異なるEC2を複数台作成する3
「vpc.tf」
38
resource "aws_vpc" "my-vpc" {
cidr_block = "10.11.0.0/16"
instance_tenancy = "default"
enable_dns_support = "true"
enable_dns_hostnames = "false"
}
resource "aws_subnet" "public" {
count = "${length(var.subnets)}"
vpc_id = "${aws_vpc.my-vpc.id}"
cidr_block = "${lookup(var.subnets[count.index], "subnet-cidr")}"
availability_zone = "${lookup(var.subnets[count.index], "subnet-az")}"
}
異なるEC2を複数台作成する4
「ec2.tf」
39
resource "aws_instance" "ec2" {
count = "${length(var.ec2-param)}"
ami = "${lookup(var.ec2-param[count.index], "ami-id")}"
instance_type = "${lookup(var.ec2-param[count.index], "ec2-instance-type")}"
key_name = "${var.keypaer-name}"
subnet_id = "${element(aws_subnet.public.*.id, "${lookup(var.ec2-param[count.index], "ec2-
subnet")}")}"
root_block_device = {
volume_type = "gp2"
volume_size = "${lookup(var.ec2-param[count.index], "ec2-volume-size")}"
}
}
異なるEC2を複数台作成する5
技術的にできるけど、めっちゃ複雑になるからやめたほうがいい。
40
EC2を作るベストプラクティス1
同じ内容のインスタンス単位を、1セクションする。
複数台の場合はLoopで作成する。
パラメータ値をMAPで外部に切り出す。
41
EC2を作るベストプラクティス2
「terraform.tfvars」
「ec2.tf」
42
ec2-param = {
ami-id = "ami-08847abae18baa040"
ec2-instance-type = "t2.micro"
ec2-volume-size = "20"
}
resource "aws_instance" "ec2" {
count = 2
ami = "${lookup(var.ec2-param, "ami-id")}"
instance_type = "${lookup(var.ec2-param, "ec2-instance-type")}"
subnet_id = “XXXXXXX”
root_block_device = {
volume_type = "gp2"
volume_size = "${lookup(var.ec2-param, "ec2-volume-size")}"
}
}
まとめ
マネコン、ダメ、ゼッタイ
IaCは覚悟の問題
Terraformは素晴らしい
43

Terraformで始めるInfrastructure as Code