今天来分享一个实际遇到的问题,背景还是在用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" "**********" {
│
经过一些研究之后,在官网发现了一些可能有帮助的内容
官网有对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的报错
而知道了问题的原因,解决的办法是什么呢?很遗憾的是目前还没看到有什么很靠谱的解决办法,因为这个限制是微软在后台设置的,在Github的一些issue里也有人遇到类似的问题,比较靠谱的思路还是从设计层面规则这类问题,主要就是指更建议使用更多更小的state文件,而不是单独一个臃肿的文件,这样可以比较好的避免类似问题
思路虽然是这样,不过实际操作其实还是有难度的,因为如果要拆出去一部分资源,还要考虑有些资源是不是已经被使用了,没办法删除了,只能把一些还可以删除的资源拿出去,先把这些资源删掉
而如果想删掉的话,又绕不过去一个问题,因为现在terraform plan都是没办法跑的,会因为请求太多而报429的错,那么就会形成一个死循环,想解决这个问题,需要terraform apply,而terraform apply需要先解决发送请求太多的问题
这里其实可以用到terraform中的一个参数,在terraform plan和terraform apply里加上-refresh=false,这样terraform会跳过refersh的步骤,直接进行最后的apply操作,就像下图一样,可以看到已经开始destroy了
这样就可以先把一部分资源destroy掉,然后放到别的state里,分摊state的大小
之后要记得再把-refresh=false拿掉,因为这个还是非常重要的,terraform就是靠这个来避免configuration dfrit这种问题的