专业的编程技术博客社区

网站首页 > 博客文章 正文

使用 Terratest 测试您的基础架构作为代码

baijin 2024-08-17 10:53:18 博客文章 9 ℃ 0 评论

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

每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?3分钟?学习?何乐而不为?,希望?大家?点赞?,评论?,加?关注?,你的?支持?是我?最大?的?动力?。
手动设置基础设施可能是一个耗时和繁忙的过程。这时我们可以使用基础结构作为代码(IaC)工具来自动化基础结构。IaC 自动化可以用于任何类型的基础设施,如虚拟机、存储等。随着越来越多的基础设施成为代码,对 IaC 进行单元测试和集成测试是非常必要的。我们将简要讨论什么是 IaC 以及测试您的基础设施代码的含义。然后我们深入研究如何使用 Terratest 进行 IaC 测试。

我们开始吧?

Infrastructure as Code (IaC)

基础设施即代码(Infrastructure as Code)是通过代码来提供和配置环境的过程,而不是通过 GUI 手动设置所需的基础设施和支持系统。例如,提供一个虚拟机,配置它,并为它设置监视。一些 IaC 的例子是 Terraform,Packer,Ansible 等。在基础设施作为代码的帮助下,您还可以将基础设施跟踪到诸如 Git 之类的版本控制系统中,进行模块化和模板化,以便在多个环境和区域中重用相同的代码。灾难恢复是编写基础设施代码的重要好处之一。使用 IaC,您可以尽快地在其他地区或环境中复制您的基础架构。

测试基础设施守则

IaC 测试可分为多个阶段:

  1. Sanity or 或者Static Analysis 静态分析
  2. Unit testing 单元测试
  3. Integration testing 集成测试

健全性或静态分析

这是测试基础结构代码的最初阶段。在静态分析中,我们确保代码具有正确的语法。它还有助于确保我们的代码符合行业标准并遵循最佳实践。短绒属于这一类。健全性测试工具的一些例子,如 Chef 的食品评论家,Docker 的 hadolint,Terraform 的 tflint 等。

单位测试

在单元测试的帮助下,我们评估我们的代码而不实际提供基础设施。例如,可以将容器限制为作为非根用户运行,或者您的组应该只使用 TCP 协议。一些单元测试示例是 Contest for Terraform 和 Chefspecs for Chef Cookbooks。

以非 root 用户身份执行的竞赛示例:

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 编写的 Infra 代码测试,为像 Amazon、 Google 这样的 IaaS 提供商或者 Kubernetes 集群打包。它为您提供各种功能和任务模式,例如:

  • 测试Docker images, Helm charts, 和Packer templates.
  • 允许使用各种云提供商 API,如 AWS 和 Azure

Terratest 为您的基础结构代码执行健全和功能测试。使用 Terratest,您可以轻松地识别当前基础结构代码中的问题,并尽快修复这个问题。我们还可以利用 Terratest 对您的基础设施进行遵从性测试,例如,在通过 IaC 创建的任何新 S3存储桶上启用版本控制和加密。

安装 Terratest 所需的二进制文件

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

安装 Terraform

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

安装完成后,运行以下命令验证是否正确安装:

terraform version


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

安装 Go

您可以使用 Linux 发行版的软件包管理器来安装 Go 或遵循 Go 的安装文档。

测试执行需要 gcc

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

Terratest 在行动

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

要事第一:

  1. 您的测试文件名应该具有比如它的名字sample_test.go. 这是 Go 查找测试文件的方式
  2. 测试函数名应该以Test T 是大写字母。例如,TestFunction 可以,但是testFunction 将给出一个错误“ no test to run”

安装 AWS 授权配置

我们需要 AWS 凭据来设置 AWS 中的基础结构; 我们可以使用环境变量或共享凭据文件来配置它。更多细节请参考 Terraform 文档。

用于基础设施的 Terraform 代码可以在组件的相应文件夹中找到。对于 ec2,它在 ec2 _ instance 下,对于 API 网关,它在 API _ gate 文件夹下。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中,我们使用延迟方法来执行清除任务,它应该是terraform destroy

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

defer terraform.Destroy(t, terraformOptions)

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

使用 Terraform. InitAndApply 我们调用 Terraform 函数 Terraform init 并应用通常用于 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 提供服务,任何方法将由 Lambda 通过 API 网关提供服务。部署之后,我们将对网关部署 URL 执行 HTTPGET 请求,并检查它是否返回成功代码。

注意: 在我们的执行中,我们没有使用任何 API _ KEY 进行身份验证,但是您应该利用它来复制 API 网关的更现实的用法。

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 来运行 HTTPGET 测试。然后,我们使用这个函数的输出作为 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 Gateway 的 department _ call _ url 执行了 HTTP GET 测试,并返回了测试状态。

使用 Terratest 测试 Terratest 模块的可扩展性和兼容性

我们也可以使用 Terratest 进行法规遵循性测试:

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

我们已经为 API 网关开发了 Terratest 检查。在本例中,我们将验证是否为您的 API 网关添加了 Authorizer。您可以了解更多关于什么是授权者的信息。

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

企业及其客户希望产品运输速度更快。基础设施即代码提供了更快的基础设施供应。随着越来越多的基础设施成为代码,对测试的需求也随之增加。在本文中,我们讨论了 Terratest 这样的工具如何在将代码部署到生产环境之前帮助验证代码。我们展示了 Terratest 是如何工作的,甚至还执行了测试用例来展示它是如何完成的。Terratest 的好处之一就是它的可扩展性,这可以通过使用本文中提到的模块来实现。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表