如何使用Terratest测试基础架构即代码

译文
开发 架构
本文简要讨论了什么是IaC以及测试基础架构代码的意义,然后深入探讨了如何使用Terratest进行IaC测试。

译者 | 布加迪

审校 | 孙淑娟

手动设置基础架构是费时又费力的过程。这时候我们可以利用基础架构即代码(IaC)工具来自动管理基础架构。IaC自动化可用于任何类型的基础架构:虚拟机和存储等。随着越来越多的基础架构变成代码,有必要为IaC进行单元测试和集成测试。

本文简要讨论了什么是IaC以及测试基础架构代码的意义,然后深入探讨了如何使用Terratest进行IaC测试。

一、基础架构即代码(IaC)

基础架构即代码是通过代码配置和设置环境的过程,而不是通过GUI手动创建所需的基础架构和支持系统。比如说,配置虚拟机、设置虚拟机并为其创建监控机制。Terraform、Packer和Ansible就是典型的IaC。借助基础架构即代码,您还可以将基础架构跟踪到Git等版本控制系统中,进行模块化和模板化,以便在多个环境和地区重用相同的代码。灾难恢复是从基础架构即代码获得的重要好处之一。有了IaC,您可以尽快在其他地区或环境复制基础架构。

二、测试基础架构代码

IaC测试可以分为多个阶段:

1.健全性或静态分析

2.单元测试

3.集成测试

  • 健全性或静态分析​

这是测试基础架构代码的初始阶段。在静态分析中,我们确保代码有正确的语法。它还有助于确保我们的代码符合行业标准,并遵循最佳实践。Linter属于这一类。几款典型的健全性测试工具包括面向Chef的foodcritic、面向Docker的hadolint和面向Terraform的tflint等。

  • 单元测试​

借助单元测试,我们不用实际配置基础架构即可评估代码。比如可以限制容器以便以非root用户身份运行,或者云网络安全组应该只有TCP协议。几个典型的单元测试是面向Terraform的Conftest和面向Chef Cookbooks的Chefspecs。

以非root用户身份执行的Conftest例子:

package main

deny[msg] {

input.kind == "Deployment"

not input.spec.template.spec.securityContext.runAsNonRoot

msg := "Containers must not run as root"

}
  • 集成测试​

在集成测试中,我们希望通过将IaC实际部署到所需的环境中对其进行测试。比如说,您部署了一个虚拟机,并在该机器的端口80上托管Nginx服务器。因此,您将在部署之后检查端口80是否在侦听。

以下是使用ServerSpec执行该操作的例子:

describe port(80) do

it { should be_listening }

end

我们在本文中介绍使用Terrratest对基础架构代码进行集成测试。

三、Terratest是什么?我们可以用它来做什么?

Terratest是由Gruntwork开发的Go库,可帮助您为使用Terraform或Packer编写的基础架构即代码创建和自动化测试。它为您提供了各种任务所需的函数和模式,比如:

测试Docker镜像、Helm图和Packer模板。

允许与各种云提供商API兼容,比如AWS和Azure。

Terratest为基础架构代码执行健全性和功能测试。有了Terratest,您可以轻松识别当前基础架构代码中的问题并尽快解决问题。我们还可以利用Terratest对基础架构进行合规测试,比如针对通过IaC创建的任何新S3存储桶启用版本控制和加密。

四、安装Terratest所需的二进制文件

Terratest主要需要Terraform和Go来执行。我们在这篇博文中使用了Terraform版本1.0.0 和Go版本1.17.6进行测试。

  • 安装Terraform​

按照Terraform网站的下载部分(https://www.terraform.io/downloads)在您的计算机上安装Terraform,您可以使用软件包管理器或下载二进制文件,并使其在PATH中可用。

安装后,通过运行以下命令验证是否已正确安装:

terraform version

Go & test依赖项安装可以通过以下步骤来完成:

  • 安装Go​

您可以使用Linux发行版的软件包管理器来安装Go,或者遵照Go的安装文档(https://go.dev/doc/install)。

  • Go测试需要gcc来执行测试​

go test命令可能需要gcc,您可以使用发行版的软件包管理器安装它。比如在CentOS/Amazon Linux 2上,您可以使用yum install -y gcc。

五、Terratest实战

现在,我们将使用Terratest执行一些集成测试。安装步骤完成后,克隆terratest-sample存储库,开始执行Terratest。我们将先使用Go编写测试并执行测试。

重要的事先说:

1.您的测试文件名称应包含_test,比如sample_test.go。这是Go查找测试文件的方式。

2.您的测试函数名称应以Test开头,其中T大写。比如说,TestFunction没有问题,但testFunction会给出错误“没有要运行的测试”。

  • 设置AWS身份验证配置​

我们需要AWS凭证在AWS中设置基础架构,可以使用环境变量或共享凭证文件进行配置。

基础架构的Terraform代码可以在组件的相应文件夹中找到。若是ec2,它位于ec2_instance下,若是API网关,它位于api_gateway文件夹下。Terratest将Terraform的output.tf的输出作为测试的输入。下面这个代码段用于测试我们是否在使用的ec2实例上有相同的ssh密钥。

package terratest
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/gruntwork-io/terratest/modules/terraform"
)
func TestEc2SshKey(t *testing.T) {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../terraform",
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
ec2SshKey := terraform.Output(t, terraformOptions, "instance_ssh_key") assert.Equal(t, "terratest", ec2SshKey)
}

我们将把它分成不同的部分以便理解:第一步,我们定义一个名为Terratest的Go软件包,然后我们导入测试执行所需的不同软件包。

package terratest
import (
"testing"
"github.com/stretchr/testify/assert" "github.com/gruntwork-io/terratest/modules/terraform"
)

一旦我们满足了所有的先决条件,将创建一个函数来执行实际测试:

func TestEc2SshKey(t *testing.T) {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../terraform",
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
ec2SshKey := terraform.Output(t, terraformOptions, "instance_ssh_key") assert.Equal(t, "terratest", ec2SshKey)
}

借助以下部分,我们定义了Terratest应该在其中查找Terraform清单文件(即main.tf和output.tf)的目录,以便创建基础架构。

terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../terraform",
})

在Go中,我们使用defer方法来执行清理任务,它应该是terraform destroy。

我们使用下面的代码片段来定义它:

defer terraform.Destroy(t, terraformOptions)

现在我们可以继续实际执行了:

使用terraform.InitAndApply ,我们调用通常用于Terraform执行的Terraform函数terraform init和apply:

terraform.InitAndApply(t, terraformOptions)

如前所述,Terratest查找来自output.tf的输出,寻找变量定义。

在下面的代码片段中,我们从Terraform输出中获取ssh密钥,并与已定义的ssh密钥名称进行匹配:

ec2SshKey := terraform.Output(t, terraformOptions, "instance_ssh_key") assert.Equal(t, "terratest", ec2SshKey)

六、执行测试

将目录切换到已克隆存储库的位置。进入到测试文件所在的位置。

初始化Go模块,并下载依赖项。请查看Terratest文档的“设置项目”部分以获取更多详细信息。

go mod init ec2_instance
go mod tidy

最后执行测试:

$ go test –v

--- PASS: TestEc2SshKey (98.72s)
PASS
ok command-line-arguments 98.735s

七、不妨继续使用Terratest

在上一节中,我们使用Terratest执行了一些基本的测试。现在,我们将通过部署一个以Lambda和ALB作为后端的API网关来执行高级测试。

  • 高级功能

API网关的GET请求将由ALB处理,任何方法将由Lambda通过API网关来处理。部署后,我们将对网关部署URL执行HTTP GET请求,并检查它是否返回成功码。

注意:我们在执行中没有使用任何API_KEY进行身份验证,但您应该使用它来再现API Gateway更实际的使用。

Terraform output.tf
output "lb_address" {
value = aws_lb.load-balancer.dns_name
description = "DNS of load balancer"
}
output "api_id" {
description = "REST API id"
value = aws_api_gateway_rest_api.api.id
}
output "deployment_invoke_url" {
description = "Deployment invoke url"
value = "${aws_api_gateway_stage.test.invoke_url}/resource"
}
  • 测试执行的代码片段

在第一个场景中,我们已经解释了基本语法,因此将直接进入测试函数。

func TestApiGateway(t *testing.T) {
//awsRegion := "eu-west-2"
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../",
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
stageUrl := terraform.Output(t, terraformOptions,"deployment_invoke_url") time.Sleep(30 * time.Second)
statusCode := DoGetRequest(t, stageUrl)
assert.Equal(t, 200 , statusCode)
}
func DoGetRequest(t terra_test.TestingT, api string) int{
resp, err := http.Get(api)
if err != nil {
log.Fatalln(err)
}
//We Read the response status on the line below.
return resp.StatusCode
}

在上面的代码片段中,我们定义了函数DoGetRequest来运行HTTP GET测试。然后,我们将此函数的输出用作TestApiGateway函数的输入。

  • 测试执行和输出
TestApiGateway 2022-03-01T06:56:18Z logger.go:66: deployment_invoke_url = "https://iuabeqgmj2.execute-api.eu-west-1.amazonaws.com/test/resource" TestApiGateway 2022-03-01T06:56:18Z logger.go:66: lb_address = "my-demo-load-balancer-
376285754.eu-west-1.elb.amazonaws.com"
TestApiGateway 2022-03-01T06:56:18Z retry.go:91: terraform [output -no-color -json deployment_invoke_url]
TestApiGateway 2022-03-01T06:56:18Z logger.go:66: Running command terraform with args [output –
no-color -json deployment_invoke_url]
TestApiGateway 2022-03-01T06:56:19Z logger.go:66: "https://iuabeqgmj2.execute-api.eu-west-
1.amazonaws.com/test/resource"
--- PASS: TestApiGateway (42.34s)
PASS
ok command-line-arguments 42.347s

如您所见,它执行了测试函数TestApiGateway,其中它对API网关的deployment_invoke_url执行了TTP GET测试,并返回了测试状态。

八、使用Terratest进行Terratest模块的 可扩展性和合规测试

我们还可以利用Terratest进行合规测试。一些例子包括:

  • 检查是否在您的SQS队列或S3存储桶上启用了加密。
  • 验证您是否为API网关设置了特定的限制。

我们为API网关开发了Terratest检查机制。在该例子中,我们验证是否为您的API网关添加了Authorizer。

目前,Terratest在其AWS模块中没有API网关模块。您可以在Terratest AWS模块目录中找到可用的AWS模块。Docker、Packer或Helm等其他Terratest模块可以在Terratest模块目录中找到。

我们使用Terratest和AWS Go SDK方法为Authorizer创建了自己的测试函数。

九、结语

企业及其客户希望产品更快速地交付。基础架构即代码加快了基础架构的配置,恰好满足了这个要求。随着越来越多的基础架构变成代码,用户对测试的需求也在增加。我们在本文中讨论了Terratest之类的工具如何帮助您在将代码部署到生产环境之前对其进行验证。我们介绍了Terratest的工作原理,甚至执行了测试用例来表明它是如何完成的。Terratest的优点之一是具有可扩展性,我们可以通过使用本文中提到的模块实现这种可扩展性。

原文链接:https://www.cncf.io/blog/2022/07/18/testing-your-infrastructure-as-code-using-terratest/

责任编辑:武晓燕 来源: 51CTO技术栈
相关推荐

2021-06-15 21:00:24

架构测试代码化

2023-02-19 15:31:09

架构软件开发代码

2020-04-17 19:41:57

基础架构即代码平台即代码云计算

2020-06-18 08:52:37

基础架构即代码

2016-04-14 09:12:20

惠普

2020-09-25 07:00:00

基础架构代码模板

2017-09-16 17:28:55

基础设施代码持续交付

2024-02-04 09:13:24

基础设施代码DevOps

2022-01-14 08:00:00

云计算云治理工具

2019-04-17 09:00:00

DevOps基础架构代码工具

2016-09-01 15:02:38

混合云多云基础架构

2016-08-30 10:39:44

云计算

2021-11-11 09:00:00

IaC工具自动化

2022-01-10 08:00:00

云原生云计算技术

2022-04-11 19:08:06

设施作用域pod

2016-08-18 16:55:00

基础设施

2022-06-17 10:24:57

IaC

2017-12-04 12:49:16

跨国互联网基础设施即代码

2022-08-12 15:47:17

工具基础架构IT

2021-07-26 09:53:58

IaC基础设施即代码云数据中心
点赞
收藏

51CTO技术栈公众号