随着越来越多的基础设施成为代码,对 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 测试可分为多个阶段:
- Sanity or 或者Static Analysis 静态分析
- Unit testing 单元测试
- 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 编写测试并执行它。
要事第一:
- 您的测试文件名应该具有比如它的名字sample_test.go. 这是 Go 查找测试文件的方式
- 测试函数名应该以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 的好处之一就是它的可扩展性,这可以通过使用本文中提到的模块来实现。
本文暂时没有评论,来添加一个吧(●'◡'●)