terraformを使ってみた
terraformって名前しか聞いたことない人やそもそも何かわからない人向けに、自分の備忘録を兼ねて書いていきます。
参考にした記事などを、各章ごとに載せているので、環境が異なる人などはそちらを参考にしてください。
今回使用したコードはgithubに載せているので、そちらを参考にしてください。
terraformとは
terraformは、インフラストラクチャをコードとして管理するためのツールです。これにより、インフラストラクチャの構成をコードとして定義し、バージョン管理や自動化が可能になります。
terraformを使用すると、インフラストラクチャの変更を簡単に追跡し、再現可能な環境を作成できます。
terraformは、AWS、Azure、Google Cloud Platformなどのクラウドプロバイダーや、VMware、OpenStackなどのオンプレミス環境に対応しています。
簡単にいうと、インフラをコードで管理するためのツールです。
terraformのインストール
今回はmacOSでのインストールを行います。
記事はこちらを参考にしました。
ただし、terraformnをダウンロードするのに、バージョン管理してくれるtfenv
を使います。
tfenvはpyenvのようなものです。
tfenvを使うことで、terraformのバージョンを簡単に切り替えることができます。
# brewでtfenvをインストール
brew install tfenv
# tfenvでterraformをインストール
tfenv install latest
# tfenvでterraformのバージョンを指定
tfenv use latest
# terafomのバージョンを確認
terraform -v
terraformを使ってみる
早速terraformを使ってみます。
はじめにterraform init
を実行する必要があるのですが、その前にtfstate
という設定ファイルを作成する必要があります。
tfstate
は、terraformが管理するインフラストラクチャの状態を保存するファイルです。
そのために、tfstateを保存するためのS3バケットを作成します。
S3バケットの作成
まず、AWSのコンソールにログインします。
AWSのコンソールからS3を開き、バケットを作成します。
バケット名はterraform-practice-tfstate-soranjiro
とします。
バケットのリージョンはap-northeast-1
を選択します。
これでtfstateを保存するためのS3バケットが作成されました。
次に、このバケットにtfstateを保存するように、terraformの設定を行います。
aws cliを使ってS3バケットを作成することもできます。
aws s3api create-bucket --bucket terraform-practice-tfstate-soranjiro --region ap-northeast-1 --create-bucket-configuration LocationConstraint=ap-northeast-1
S3バケットの名前はグローバルで一意である必要があります。
同じ名前のバケットが存在する場合は、別の名前を指定してください。
ユーザ名やプロジェクト名を入れると良いでしょう。
terraformの設定
terraformの設定ファイルを作成します。
ファイル名はなんでも良いです。
直下に置かれた.tf
ファイルを全て読み込むので、main.tf
やterraform.tf
などの名前をつけることが多いです。
terraform {
required_version = ">= 0.12"
backend "s3" {
bucket = "terraform-practice-tfstate"
key = "terraform.tfstate"
region = "ap-northeast-1"
}
}
provider "aws" {
region = "ap-northeast-1"
}
これで、terraformの設定が完了しました。
terraformの初期化
次に、terraformを初期化します。
terraform init
これで、terraformの初期化が完了しました。
awsの認証情報がないと以下のようなエラーが出ます。
╷
│ Error: No valid credential sources found
│
│ Please see https://www.terraform.io/docs/language/settings/backends/s3.html
│ for more information about providing credentials.
│
│ Error: failed to refresh cached credentials, no EC2 IMDS role found, operation error ec2imds: GetMetadata, exceeded maximum number of attempts, 3, request send failed, Get
│ "http://169.254.169.254/latest/meta-data/iam/security-credentials/": dial tcp 169.254.169.254:80: connect: no route to host
│
╵
この場合は、aws cliの認証情報を設定する必要があります。
brew install awscli
aws configure
.terraform
という隠しフォルダが作成されてterraform.tfstate
というファイルたちが作成されていたら成功です。
lambdaの作成
せっかくなので、lambda関数を作成してみます。
lambda関数は、AWSのサーバーレスコンピューティングサービスです。
簡単にいうと、コードを書くだけで環境とかはAWSが用意してくれるサービスです。
ディレクトリ構成は以下のようにします。
sample
├── lambda # Lambda関数をまとめたディレクトリ
│ └── hello-world # TerraformのLambdaモジュール
│ ├── sample
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── main.tf
├── main.tf
└── provider.tf
最終的には、以下のようにしたいですが、一回でterraform apply
ができなくなってしまうので一旦上に書いたようにします。
├─ env
│ ├─ dev
│ ├─ prod
│ │ └─ lambda
│ └─ stg
└─ modules
└─ lambda
main.tf
# main.tf
module "hello_world" {
source = "./lambda/hello-world"
}
provider.tf
# provider.tf
terraform {
required_version = ">= 0.12"
backend "s3" {
bucket = "terraform-practice-tfstate-soranjiro"
key = "terraform.tfstate"
region = "ap-northeast-1"
}
}
provider "aws" {
region = "ap-northeast-1"
}
hello-world/main.tf
# lambda/hello-world/main.tf
##################################
# Lambdaに付与するロール #
##################################
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
actions = ["sts:AssumeRole"]
}
}
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
##################################
# Lambda #
##################################
resource "terraform_data" "default" {
triggers_replace = {
always_run = timestamp()
}
provisioner "local-exec" {
command = "cd ${path.module}/sample/ && GOOS=linux GOARCH=amd64 go build -o ./build/bootstrap main.go"
}
}
data "archive_file" "lambda" {
type = "zip"
source_file = "${path.module}/sample/build/bootstrap"
output_path = "${path.module}/sample/go.zip"
depends_on = [ terraform_data.default ]
}
resource "aws_lambda_function" "hellow_world" {
filename = "${path.module}/sample/go.zip"
function_name = "hello-world"
role = aws_iam_role.iam_for_lambda.arn
handler = "sample"
source_code_hash = data.archive_file.lambda.output_base64sha256
runtime = "provided.al2023"
}
hello-world/sample/main.go
// lambda/hello-world/sample/main.go
package main
import (
"context"
"fmt"
"github.com/aws/aws-lambda-go/lambda"
)
type MyEvent struct {
Name string `json:"name"`
}
func HandleRequest(ctx context.Context, name MyEvent) (string, error) {
return fmt.Sprintf("Hello %s!", name.Name), nil
}
func main() {
lambda.Start(HandleRequest)
}
cd lambda/hello-world
go mod init lambda/hello-world
go mod tidy
これで、lambda関数の準備ができました。
lambda関数のデプロイ
次に、lambda関数をデプロイします。
terraform init
terraform apply
# yesと入力
**Apply complete!**とでたら成功です。
もし、権限エラーで失敗している場合は、IAMロールの権限を確認してください。
PowerUserAccess
とIAMFullAccess
を付与したら(ほぼできないことないので当たり前ですが)できると思います。
自分に必要な権限だけを付与するように不必要な権限は削除していきましょう!
lambda関数の確認
実際に作成されたかを確認してみましょう。
AWSコンソールから確認
AWSのコンソールから作成されたことが確認できると思います。
lambdaのコンソールから、関数を選択して、テストを実行してみましょう。
{
"name": "soranjiro"
}
実行結果は以下のようになります。
{
"statusCode": 200,
"body": "\"Hello soranjiro!\""
}
aws cliから確認
ついでに、aws cliで確認してみましょう。
# 実行可能なlambda関数の一覧を取得
aws lambda list-functions --region ap-northeast-1
これで、hello-world
という関数が作成されていることが確認できると思います。
次に、lambda関数を実行してみましょう。
# lambda関数を実行
aws lambda invoke \
--function-name hello-world \
--cli-binary-format raw-in-base64-out \
--payload '{"name": "World"}' \
response.json
このコマンドの内容は、
-
--function-name
: 実行するlambda関数の名前 -
--cli-binary-format
: aws cliのバージョン2以降で必要なオプション -
--payload
: lambda関数に渡す引数- json形式で、
name
というキーにWorld
という値を渡しています。 - キーを変更することで、別のレスポンスを得ることができます。
- json形式で、
-
response.json
: 実行結果を保存するファイル名
実行結果は、ターミナルに出力され、bodyの部分(lambdaからのレスポンス)はresponse.json
に保存されます。
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
response.json
の中身は以下のようになります。
"Hello World!"
lambda関数の削除
terraformで作成したリソースは、terraform destroyコマンドで削除することができます。
terraform destroy
# yesと入力
Destroy complete! Resources: 3 destroyed.
と表示されれば成功です。
以下のように、lambda関数が削除されていることを確認できます。
% aws lambda list-functions --region ap-northeast-1
{
"Functions": []
}