使用Terratest测试你的基础设施即代码

331 阅读9分钟

DZone>DevOps Zone>使用Terratest测试你的基础设施即代码

使用Terratest测试你的基础设施即代码

随着越来越多的基础设施成为代码,对你的IaC进行单元和集成测试是非常必要的。什么是IaC和测试你的基础设施代码意味着什么?

Akash Warkhade user avatar 通过

阿卡什-瓦克哈德

-

6月23日,22 - DevOps Zone -教程

喜欢 (1)

评论

保存

鸣叫

352次浏览

加入DZone社区,获得完整的会员体验。

免费加入

手动设置基础设施可能是一个耗时而忙碌的过程。这时,我们可以利用基础设施即代码 (IaC)工具来实现基础设施的自动化。IaC自动化可用于任何类型的基础设施,如虚拟机、存储等。随着越来越多的基础设施成为代码,为你的IaC进行单元和集成测试是至关重要的。我们将简要地讨论什么是IaC和测试你的基础设施代码的含义。然后,我们将深入探讨如何使用Terratest进行IaC测试。

让我们开始吧,好吗?

基础设施即代码(IaC)

基础设施即代码是指通过代码配置环境的过程,而不是通过GUI手动设置所需的基础设施和支持系统。例如,配置一个虚拟机,配置它,并为它设置监控。一些IaC的例子是Terraform、Packer、Ansible等。在基础设施即代码的帮助下,你也可以将你的基础设施跟踪到一个版本控制系统中,如Git,模块化和模板化,以便在多个环境和地区重复使用相同的代码。灾难恢复是你从编码的基础设施中得到的重要好处之一。通过IaC,你可以尽快在其他地区或环境中复制你的基础设施。

测试基础设施代码

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

  1. 真理静态分析
  2. 单元测试
  3. 集成测试

正常性或静态分析

这是测试基础设施代码的最初始阶段。在静态分析中,我们确保我们的代码有正确的语法。它还有助于确保我们的代码符合行业标准并遵循最佳实践。林特人就属于这一类。理性测试工具的一些例子是Chef的foodcritic,Docker的hadolint,Terraform的tflint,等等。

单元测试

在单元测试的帮助下,我们评估我们的代码,而不需要实际配置基础设施。例子可以是限制你的容器以非root用户的身份运行,或者你的组只应该有TCP协议。一些单元测试的例子是Terraform的Conftest和Chefspecs的Chef Cookbooks。

以非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为亚马逊、谷歌等IaaS供应商编写的Infra作为代码创建和自动测试,或者为Kubernetes集群创建测试。它为你提供了各种功能和模式的任务,如。

  • 测试Docker镜像,Helm图表,以及Packer模板。
  • 允许与各种云提供商的API合作,如AWS和Azure。

Terratest为你的基础设施代码执行合理性和功能测试。有了Terratest,你可以很容易地发现当前基础设施代码中的问题,并尽快修复问题。我们还可以利用Terratest对您的基础设施进行合规性测试,例如,在通过您的IaC创建的任何新S3桶上启用版本控制和加密。

安装Terratest所需的二进制文件

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

安装Terraform

按照Terraform网站的下载部分,在你的机器上安装Terraform;你可以使用软件包管理器或下载二进制文件,并使其在PATH中可用。

安装后,通过运行下面的命令来验证它是否正确安装。

terraform version

Go & test依赖性的安装可以通过以下步骤完成。

安装Go

你可以使用你的Linux发行版的软件包管理器来安装Go,或者按照Go的安装文档来安装。

go test 测试执行需要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文档

基础设施的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.tfoutput.tf ,用于创建基础设施。

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

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

我们使用下面的片段来定义它。

defer terraform.Destroy(t, terraformOptions)

现在我们可以进入实际执行阶段。

通过terraform.InitAndApply ,我们正在调用Terraform函数terraform initapply ,我们通常使用这些函数来执行Terraform。

  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提供,ANY方法将由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 进行了HTTP GET测试并返回了测试状态。

Terratest模块的扩展性和使用Terratest的合规性测试

我们也可以利用Terratest进行合规性测试。其中一些例子可以是。

  • 检查您的SQS队列或S3桶是否启用了加密功能。
  • 验证您是否为API网关设置了特定的节流限制。

我们已经为API网关开发了一个Terratest检查。在这个例子中,我们正在验证是否为您的API网关添加了Authorizer 。你可以找到更多关于什么是授权者的信息。

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

企业和他们的客户都希望产品能更快地被运出。基础设施即代码(Infrastructure as Code)正是通过加快基础设施的配置来实现的。随着越来越多的基础设施成为代码,对测试的需求也在增加。在这篇文章中,我们讨论了像Terratest这样的工具如何在你将代码部署到生产之前帮助验证你的代码。我们展示了Terratest是如何工作的,甚至还执行了测试案例来展示它是如何完成的。Terratest的优点之一是它的可扩展性,可以通过使用模块来实现,正如文章中所谈到的。

API AWS 基础设施 基础设施即代码 Docker(软件) Terraform(软件)测试

经Akash Warkhade许可发表于DZone。点击这里查看原文。

DZone贡献者所表达的观点属于他们自己。

DZone上的热门文章


评论

DevOps 合作伙伴资源