今天来分享一个实际遇到的问题,背景还是在用terraform部署Azure资源,其中在部署private dns zone的时候,因为每个VNET都要link到dns zone,加上需要部署的DNS Zone又比较多,叠加在一起就导致terraform需要创建几百甚至上千个资源

创建这些资源本身没什么问题,但是在之后更新一些资源的属性时遇到一个比较奇怪的现象,在进行terraform plan的时候一直会遇到一个报错StatusCode=429 -- Original Error: context deadline exceeded,开始以为是网络问题,等到第二天再试的发现还是一直会重复遇到这个报错,报错内容大概如下:

Error: reading Virtual Network Link (Subscription: "**********"
│ Resource Group Name: "**********"
│ Private Zone Name: "privatelink.chinacloudsites.cn"
│ Virtual Network Link Name: "vnet-link-**********"): virtualnetworklinks.VirtualNetworkLinksClient#Get: Failure sending request: StatusCode=429 -- Original Error: context deadline exceeded
│ 
│   with azurerm_private_dns_zone_virtual_network_link.**********,
│   on privatelink.chinacloudsites.cn.tf line 196, in resource "azurerm_private_dns_zone_virtual_network_link" "**********":
│  196: resource "azurerm_private_dns_zone_virtual_network_link" "**********" {
│ 

解决Terraform StatusCode=429问题_Azure

经过一些研究之后,在官网发现了一些可能有帮助的内容

https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/request-limits-and-throttling#error-code

官网有对429这个status code做了一些介绍,主要是因为发送了太多次请求,导致后续发的请求不会再被接收,继而抛出了这个error

When you reach the limit, you receive the HTTP status code 429 Too many requests. The response includes a Retry-After value, which specifies the number of seconds your application should wait (or sleep) before sending the next request. If you send a request before the retry value has elapsed, your request isn't processed and a new retry value is returned.

After waiting for specified time, you can also close and reopen your connection to Azure. By resetting the connection, you may connect to a different instance of Azure Resource Manager.

而为什么会发送这么多请求,主要原因是terraform在plan的时候默认会进行refresh的操作,refresh主要目的是看下在上一次apply之后资源的状态和state文件里记录的是不是还能匹配上,如果不匹配则会进行修复,这就导致了需要发送大量的请求来查看资源的状态,这样也能解释为什么会出现这个429的报错

解决Terraform StatusCode=429问题_云_02

而知道了问题的原因,解决的办法是什么呢?很遗憾的是目前还没看到有什么很靠谱的解决办法,因为这个限制是微软在后台设置的,在Github的一些issue里也有人遇到类似的问题,比较靠谱的思路还是从设计层面规则这类问题,主要就是指更建议使用更多更小的state文件,而不是单独一个臃肿的文件,这样可以比较好的避免类似问题

思路虽然是这样,不过实际操作其实还是有难度的,因为如果要拆出去一部分资源,还要考虑有些资源是不是已经被使用了,没办法删除了,只能把一些还可以删除的资源拿出去,先把这些资源删掉

而如果想删掉的话,又绕不过去一个问题,因为现在terraform plan都是没办法跑的,会因为请求太多而报429的错,那么就会形成一个死循环,想解决这个问题,需要terraform apply,而terraform apply需要先解决发送请求太多的问题

这里其实可以用到terraform中的一个参数,在terraform plan和terraform apply里加上-refresh=false,这样terraform会跳过refersh的步骤,直接进行最后的apply操作,就像下图一样,可以看到已经开始destroy了

解决Terraform StatusCode=429问题_Azure_03

这样就可以先把一部分资源destroy掉,然后放到别的state里,分摊state的大小

之后要记得再把-refresh=false拿掉,因为这个还是非常重要的,terraform就是靠这个来避免configuration dfrit这种问题的