LoginSignup
2
1

More than 1 year has passed since last update.

Terraformをローカル環境でのインストールをせずにDockerの公式イメージから利用する

Last updated at Posted at 2022-05-02

(2022/5/17) Makefileに記述しているdockerコマンドの環境変数他加筆。

はじめに

老体に鞭打ってawsに取り組んでいる昨今だが、どうもGUIというかウェブ画面での操作に慣れない。
慣れないというよりやり方を記録しておくのにわざわざスクリーンショットを取るのが煩わしいのだ。

「そんなあなたにCloudFormation」というのがaws的な流儀なんだろうから一応トライしてみているが、全作業がローカルのターミナルから完結するわけではないのと設定ファイルが難解なのでもう少しなんとかならないかと考えていた。
そこで対抗場として挙げられるのがTerraformなのでそのうちやろうと思いつつようやく重い腰を上げてやってみた。

ちなみに以下のリンクのようにaws-cliのみでごりごりやるのはそれはそれですごいけど若干ついて行けない。

AWS Fargateを使って、マイクロサービス環境を実現する - 革命のブログ

また以下の例はDockerイメージを使っているもののコンテナ内のシェルにログインして利用しているのでちょっと自分のやりたい方法とは違う。

DockerでTerraformを使う

環境

  • os: Linux Mint 19.1 Tessa
  • docker: 20.10.14
  • make: 4.1(無くてもよいし使わなくてもよい)
  • aws-cli: 2.4.24

makeは無くても構わないけどコマンドラインが恐ろしく長くなるし標準的なLinuxだとデフォルトで入ってるだろうから使ったほうがよい。
後、aws-clicredentials情報が作成済みなら今回の作業自体では要らないけどまあ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のセットアップをしておく。

10分で理解するTerraform - Qiita

そして元ネタリンクから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.tfprofileを使わないように修正し(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_IDAWS_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環境で実行するにはbashawkも必要だしそもそもpwdとかの設定があるのでGit BashWSLとかでないときちんと動かないと思う。

CloudFormationより設定ファイルが読みやすいとはいいきれないかもしれないが、今の所Terraformのほうがしっくりくる。
ただ両者いずれにしてもウェブのコンソールから実際操作してみないと何をやっているのかどこの箇所の入力をしているのかわからないというのが難点ではある。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1