(2022/5/17) Makefile
に記述しているdocker
コマンドの環境変数他加筆。
はじめに
老体に鞭打ってaws
に取り組んでいる昨今だが、どうもGUI
というかウェブ画面での操作に慣れない。
慣れないというよりやり方を記録しておくのにわざわざスクリーンショットを取るのが煩わしいのだ。
「そんなあなたにCloudFormation
」というのがaws
的な流儀なんだろうから一応トライしてみているが、全作業がローカルのターミナルから完結するわけではないのと設定ファイルが難解なのでもう少しなんとかならないかと考えていた。
そこで対抗場として挙げられるのがTerraform
なのでそのうちやろうと思いつつようやく重い腰を上げてやってみた。
ちなみに以下のリンクのようにaws-cli
のみでごりごりやるのはそれはそれですごいけど若干ついて行けない。
AWS Fargateを使って、マイクロサービス環境を実現する - 革命のブログ
また以下の例はDocker
イメージを使っているもののコンテナ内のシェルにログインして利用しているのでちょっと自分のやりたい方法とは違う。
環境
-
os
: Linux Mint 19.1 Tessa -
docker
: 20.10.14 -
make
: 4.1(無くてもよいし使わなくてもよい) -
aws-cli
: 2.4.24
make
は無くても構わないけどコマンドラインが恐ろしく長くなるし標準的なLinux
だとデフォルトで入ってるだろうから使ったほうがよい。
後、aws-cli
はcredentials
情報が作成済みなら今回の作業自体では要らないけどまあaws
さわるなら必須だと思う。
実作業
以下のリンク(以下、元ネタリンク)のサンプルを元にec2
インスタンスを作成してみる。
Terraform入門 AWSにEC2を作成してみよう - たけログ
最新版公式イメージのバージョン確認
とりあえずTerraform
のバージョンだけ確認
docker run -it hashicorp/terraform:latest version
結果
Terraform v1.1.9
on linux_amd64
事前準備
実際にaws
を利用するためにはcredentials
情報が必要となる。以下のサイトを参考にIAM
ユーザーの作成やaws cli
のセットアップをしておく。
そして元ネタリンクからmain.tf
をコピーして実行する。
で
docker run hashicorp/terraform:latest init
としたいのだが、設定ファイル(*.tf
)が無いと怒られる。
Terraform initialized in an empty directory!
The directory has no Terraform configuration files. You may begin working
with Terraform immediately by creating Terraform configuration files.
最初のはまりポイント
ローカル環境にmain.tf
を準備してもコンテナのイメージ内からは見れない(存在しない)。
なのでvolume
マウント(-v
オプション)し、かつ作業ディレクトリ(-w
オプション)にも設定する。
マウント先はroot
権限でしか書き込みできないディレクトリだと後々不便なので/opt
とか/var/tmp
とかにしてみる。
公式イメージが
alpine
のようなのでこのあたりのディレクトリは非root
でも書き込めると判断
なので訂正版
docker run -v $(pwd):/opt -w /opt hashicorp/terraform:latest init
結果
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 3.0"...
- Installing hashicorp/aws v3.75.1...
- Installed hashicorp/aws v3.75.1 (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!
うまくいった。よし。
次のはまりポイント
ではplan
実行。標準入力が求められるので-it
オプションを追加する。
docker run -it -v $(pwd):/opt -w /opt hashicorp/terraform:latest plan
profile
の入力画面
var.aws_profile
Enter a value:
ここで作成済みのprofile
を入力するも。。。
│ Error: error configuring Terraform AWS Provider: no valid credential sources for Terraform AWS Provider found.
これはprofile
が見つからないとういエラーで先程の例と同じくローカルの~/.aws/credentilas
がコンテナ内からはアクセスできないからだ。
なのでマウントしてもよいが、ここは以下のようにmain.tf
をprofile
を使わないように修正し(variable "aws_profile" {}
をコメントアウト)、
--- main.tf.orig 2022-05-02 13:09:15.275770436 +0900
+++ main.tf 2022-05-02 13:09:20.695725517 +0900
@@ -5,8 +5,8 @@
type = string
default = "ap-northeast-1"
}
-variable "aws_profile" {
-}
+#variable "aws_profile" {
+#}
variable "amis" {
type = map(string)
そしてAWS_ACCESS_KEY_ID
とAWS_SECRET_ACCESS_KEY
という環境変数を設定して実行する。
docker run -it -e AWS_ACCESS_KEY_ID=my-key -e AWS_SECRET_ACCESS_KEY=my-secret -v $(pwd):/opt -w /opt hashicorp/terraform:latest plan
よし成功。
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.terraform-example will be created
...
ここで真打ち登場
ここまで来るとコマンドが恐ろしく長いことに気づくはず。
そこで真打ちGNU Make
の登場となる。
例えば上記コマンドは以下のようにすっきりする。
make init
make plan
実装
具体的には以下のようなファイル構成にする。
├── .env
├── Makefile
└── main.tf
.env
(各変数は自分のユーザ情報を記述)
AWS_ACCESS_KEY_ID=<YOUR ACCESS KEY>
AWS_SECRET_ACCESS_KEY=<YOUR SECRET ACCESS KEY>
これまで紹介したコマンドラインのオプションに加え、実行ユーザやログ出力のオプションを加えたMakefile
の完成形がこちら。
MAKEFLAGS += --warn-undefined-variables
SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
# all targets are phony
.PHONY: $(shell egrep -o ^[a-zA-Z_-]+: $(MAKEFILE_LIST) | sed 's/://')
DOCKER_IMAGE=hashicorp/terraform:latest
WORK_DIR=/opt
U_ID=1000
G_ID=1000
AWS_ACCESS_KEY_ID=my-key
AWS_SECRET_ACCESS_KEY=my-secret
TF_LOG=DEBUG
TF_LOG_PATH=debug.log
# .env
ifneq ("$(wildcard ./.env)","")
include ./.env
endif
export CMD
override define CMD
/usr/bin/docker run -it -u ${U_ID}:${G_ID} \
-e TZ=Asia/Tokyo \
-e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
-e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
-e HOME=${WORK_DIR} \
-e TF_LOG=${TF_LOG} \
-e TF_LOG_PATH=${TF_LOG_PATH} \
-v ${PWD}:${WORK_DIR} \
-w ${WORK_DIR} \
${DOCKER_IMAGE}
endef
version: ## Show terraform version
@${CMD} -v
terraform-help: ## Show terraform help
@${CMD} -help
init: ## Prepare working directory
@${CMD} init
validate: ## Validation configuration file (*.tf)
@${CMD} validate
fmt: ## Format configuration file (*.tf)
@${CMD} fmt
plan: ## Show plan
@${CMD} plan
apply: ## Create or update infrastructure
@${CMD} apply
apply-auto-approve : ## Create or update infrastructure with -auto-approve
@${CMD} apply -auto-approve
show: ## Show the plan
@${CMD} show
output: ## Output resource
@${CMD} output
destroy: ## Create or update infrastructure
@${CMD} destroy
destroy-auto-approve: ## Create or update infrastructure -auto-approve
@${CMD} destroy -auto-approve
help: ## Print this help
@echo 'Usage: make [target]'
@echo ''
@echo 'Targets:'
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9_-]+:.*?## / {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
Makefileのポイント解説
環境変数を利用するため、.env
を用いる。
同一階層の.env
を読み込むための設定が以下。
# .env
ifneq ("$(wildcard ./.env)","")
include ./.env
endif
ただし.env
存在しない、または.env
内や環境変数が存在しない場合に備えて事前にデフォルト値を設定しておくほうがよい。
実行ユーザの
UID
(変数名はU_ID
)とGID
(変数名はG_ID
)をローカル実行環境と合わせておくと出力ファイル(terraform.tfstate
等)のパーミッションが統一される。
というか設定しないとroot
のパーミッションとなる。
(2022/5/17)追記
Terraform
は実行時に~/.terraform.d
というディレクトリを(無ければ)作成するのでHOME
も設定するようにした。
DOCKER_IMAGE=hashicorp/terraform:latest
WORK_DIR=/opt
U_ID=1000
G_ID=1000
AWS_ACCESS_KEY_ID=my-key
AWS_SECRET_ACCESS_KEY=my-secret
TF_LOG=DEBUG
TF_LOG_PATH=debug.log
そうすると.env
に書き込まれた変数だけがオーバライトされる。
.env
でなくtfvars
運用でも構わない。
いずれにしてもMakefile
からは外出ししてGit
の管理対象外(.gitignore
)にしておくことが望ましい。
Docker
のコマンドが何度も出てくるのでCMD
という変数に置き換えるが、ワンライナーで書くと長ったらしいので以下のようにする。
export CMD
override define CMD
/usr/bin/docker run -it -u ${U_ID}:${G_ID} \
-e TZ=Asia/Tokyo \
-e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
-e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
-e HOME=${WORK_DIR} \
-e TF_LOG=${TF_LOG} \
-e TF_LOG_PATH=${TF_LOG_PATH} \
-v ${PWD}:${WORK_DIR} \
-w ${WORK_DIR} \
${DOCKER_IMAGE}
endef
後はこんな感じでタスク設定ができる。
init: ## Prepare working directory
@${CMD} init
準備ができたら
既に説明した
make init
make plan
までできたら実際にaws
への適用(デプロイ)は
make apply
成果物の削除は
make destroy
となる。
困ったときは以下でオプションを調べてMakefile
のタスクに登録すればよい。
make terraform-help
まとめ
Terraform
利用歴2日目のため、理解不足の面があるかもしれないことは予めお断りしておく。
しかし初期化、作成、デプロイ、削除と一通りのコマンドは実行できることを確認した。
GNU Make
を使うといちいちコマンドを覚えなくて良いのと(設定によるが)入力補完が効くので大変便利である。
Windows
環境でもGNU Make
のバイナリは提供されていると後、Docker
さえインストールされていればTerraform
はインストールしなくてよいのでとっつきやすいのではないだろうか。
とはいえ
Windows
環境で実行するにはbash
やawk
も必要だしそもそもpwd
とかの設定があるのでGit Bash
やWSL
とかでないときちんと動かないと思う。
CloudFormation
より設定ファイルが読みやすいとはいいきれないかもしれないが、今の所Terraform
のほうがしっくりくる。
ただ両者いずれにしてもウェブのコンソールから実際操作してみないと何をやっているのかどこの箇所の入力をしているのかわからないというのが難点ではある。