不需要在本地安装Terraform,直接使用Docker官方镜像

(2022年5月17日)增加了Makefile文件中的docker命令的环境变量等信息。

首先

目前,人们正积极投入到AWS的学习中,但似乎对于GUI操作或者说通过网页界面进行操作并不习惯。
更确切地说,不是不习惯,而是觉得记录步骤时需要大费周章地截屏太过麻烦。

因为你这样的人是亚马逊云的主要流派,所以我尝试了一下CloudFormation,但并不是所有的操作都能在本地终端上完成,而且配置文件也相当复杂,所以我在考虑是否能有其他更好的选择。
于是,我看到了可以作为对手的Terraform,所以我决定要试试它。虽然一直迟迟没有开始,但我最终还是鼓起了勇气。

顺便提一下,像以下链接中那样只使用aws-cli来进行操作虽然很厉害,但有点跟不上节奏。

使用AWS Fargate来实现微服务环境-革命的博客

由于使用了Docker镜像并登录到容器内的shell来使用,因此下面的例子与我想要的方法有点不同。

使用 Docker 运行 Terraform

环境

Note: The given phrase “环境” is already in Chinese. Therefore, there is no need to paraphrase it.

os: Linux Mint 19.1 Tessa

docker: 20.10.14

make: 4.1(無くてもよいし使わなくてもよい)

aws-cli: 2.4.24

可以不用make,但命令行会变得非常冗长,而且在标准的Linux中,它应该已经默认安装了,所以最好使用它。
另外,如果已经创建了AWS-cli的凭证信息,在这次操作中就不需要它,但我认为如果要与AWS打交道的话,它是必需的。

实际操作

根据以下链接(以下简称原始链接)提供的样本,尝试创建EC2实例。

让我们试着使用Terraform在AWS上创建一个EC2实例 – たけログ

确认最新版公式图像的版本

先确认一下Terraform的版本。

docker run -it hashicorp/terraform:latest version

结局

Terraform v1.1.9
on linux_amd64

事前准备可以翻译为 “预先准备”。

为了使用AWS,需要凭证信息。请参考以下网站创建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,但在容器镜像内无法查看(不存在)。
因此需要挂载卷(-v选项),并设置工作目录(-w选项)。
由于挂载目标只能以root权限进行写入,选择/opt或/var/tmp等目录会更为方便。

由于该公式的形象类似于阿尔卑斯山,因此可以判断这个目录在非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!

做得很好。好极了。

以下是潮流指標

执行计划。因为需要标准输入,所以添加-it选项。

docker run -it -v $(pwd):/opt -w /opt hashicorp/terraform:latest plan

个人资料输入界面

var.aws_profile
  Enter a value: 

在这里输入已经创建好的个人资料…

│ Error: error configuring Terraform AWS Provider: no valid credential sources for Terraform AWS Provider found.

这是一个错误,说找不到配置文件,原因是之前的例子中类似的问题,本地的~/.aws/credentials文件在容器内无法访问。
所以可以尝试挂载,但是也可以通过修改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文件中写入的变量会被覆盖掉。

可以使用tfvars进行运维,而不是.env文件。无论哪种方式,最好将其从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的使用经验仅有两天,可能存在理解不足的情况,请事先注意。
不过我已经确认可以执行初始化、创建、部署和删除等一系列命令。

如果使用GNU Make,就不需要记住每个命令(根据设置而定),而且它还具有输入补全功能,非常方便。
而且,在Windows环境下,GNU Make的二进制文件也是可用的。只要安装了Docker,就不需要安装Terraform,所以它可能更易于上手。

然而,在Windows环境下运行需要使用bash或awk,并且还需要进行一些诸如pwd之类的配置,所以我认为如果不使用Git Bash或WSL,它可能无法正常工作。

虽然不能断言Terraform的配置文件比CloudFormation更易读,但目前来看,Terraform更加合适。
然而,无论选择哪个工具,都存在一个难点,就是如果不亲自在网络控制台上进行操作,就无法了解具体在做什么,以及在哪个部分进行输入。

广告
将在 10 秒后关闭
bannerAds