基础设施即代码--Terraform 踩坑记1

Terraform 踩坑记1

最近在使用 Terraform 部署 Azure AKS 集群,遇到了一些问题,把问题的根因和排查过程做个记录。

关于什么是 Terraform 请参照前文。
https://github.com/cai11745/hybrid-cloud/blob/master/terraform/2023-02-24-terraform-install-and-simple-demo.md
简单说就是以编码文件的方式,定义你所有创建的资源,而不需要通过页面或者命令行去操作,便于快速创建与销毁,配合git还可以做好版本管理。

关于本次问题排查,先上总结,再细细道来:

  1. 通过Azure CLI或者Azure Portal创建出来的资源,与通过 Terraform 创建时,有些参数的默认值不同的。比如这次遇到的
    subnet 的 privateEndpointNetworkPolicies 属性,通过 portal 创建默认是 disabled。而通过 terraform 创建的 subnet 这个参数默认是 enabled。
  2. 资源属性的对比,除了在 portal 上对比参数配置。还可以借助命令行或者查看资源的JSON文件获取更多信息。因为有些参数在 portal 是不显示的。这次的 subnet 就是这样,在 portal 上和之前创建的 subnet 对比了几次没发现异常。
  3. 资源创建或者操作失败的时候,如何追踪到更多的报错信息。查看 Activity log,包括你创建的资源、资源所在资源组、资源关联的vnet/路由表等、资源衍生出来的资源组(比如AKS创建时会自动衍生出一个新的资源组)

环境信息

已有 vnet 为 net001,已经通过 portal 创建了 subnet1 子网,通过 azure cli 命令创建了一个 AKS 集群 aks1 部署在 subnet1 ,运行正常。

本次目标是创建 aks2 主要流程和资源如下,与 aks1 无异:

  1. 创建aks 所在资源组
  2. 创建subnet2 子网,定义网段
  3. 创建自定义路由表
  4. 创建自定义aks master托管标识
  5. 对路由表授予托管标识 "Network Contributor" 权限
  6. 创建aks:开启 private cluster,使用自定义托管标识,定义节点池的规格、数量、子网,定义网络插件、网络出口采用自定义路由

本次的最大差异是 aks1 及相关资源通过 azure portal 和azure cli 创建。 而本次 aks2 将采用 terraform 创建,将通过 terraform 定义上述的所有资源和role分配。

排障过程

报错内容

当我执行 terraform apply 之后,aks 之前的资源都创建成功,但 aks 这部分报错了,而且这个报错内容有点难以理解,网上也没有查到有用信息。

azurerm_kubernetes_cluster.k8s: Still creating... [1m10s elapsed]
azurerm_kubernetes_cluster.k8s: Still creating... [1m20s elapsed]
azurerm_kubernetes_cluster.k8s: Still creating... [1m30s elapsed]
azurerm_kubernetes_cluster.k8s: Still creating... [1m40s elapsed]
azurerm_kubernetes_cluster.k8s: Still creating... [1m50s elapsed]
azurerm_kubernetes_cluster.k8s: Still creating... [2m0s elapsed]
╷
│ Error: waiting for creation of Managed Cluster (Subscription: "xxxxxx-xxxxxx-xxxxxx"
│ Resource Group Name: "xxxxxx"
│ Managed Cluster Name: "aks2-xxxxx"): Code="InternalOperationError" Message="Internal server error"
│
│   with azurerm_kubernetes_cluster.k8s,
│   on main.tf line 59, in resource "azurerm_kubernetes_cluster" "k8s":
│   59: resource "azurerm_kubernetes_cluster" "k8s" {
│

排查过程

首先做的是把资源删了 terraform destroy,再 apply 来一次,结果还是一样的报错。

aks 的 Activity log 上看到的报错和 terraform 返回的内容是一样的,就是 Code="InternalOperationError" Message="Internal server error",所以 terraform 返回没有遗漏信息。
且 aks 的状态显示异常,但是未给出更多信息。aks 每次创建时会自动创建一个新的资源组 node-resource-group,默认会叫 MC_rg_xxx ,用于放置 node 相关资源,比如 kubelet 托管标识、VirtualMachineScaleSets(node虚拟机集)、k8s loadbalance、network security group、private dns。通过 AKS 页面的 Properties -- Infrastructure resource group 进入,正常情况下 aks 创建完能看到6,7个资源,而此时只看到两个资源:node托管标识和NSG,所以判定 k8s的配置文件有问题,也就是下面这一段。

我先后尝试精简化配置,把 linux_profile 和其他能够移除的部分都拿掉了,还是创建依然没有成功。

resource "azurerm_kubernetes_cluster" "k8s" {
  depends_on = [azurerm_role_assignment.route_table_network_contributor, azurerm_subnet_route_table_association.rt1_sub1]

  location                = azurerm_resource_group.rg.location
  name                    = var.cluster_name
  resource_group_name     = azurerm_resource_group.rg.name
  dns_prefix              = var.dns_prefix
  private_cluster_enabled = true

  identity {
    type         = "UserAssigned"
    identity_ids = [azurerm_user_assigned_identity.uai_master.id]
  }

  #  kubelet_identity {
  #    client_id                 = azurerm_user_assigned_identity.uai_node.client_id
  #    object_id                 = azurerm_user_assigned_identity.uai_node.principal_id
  #    user_assigned_identity_id = azurerm_user_assigned_identity.uai_node.id
  #  }

  default_node_pool {
    name           = "agentpool"
    vm_size        = var.agent_vm_size
    node_count     = var.agent_count
    vnet_subnet_id = azurerm_subnet.sub1.id
    type           = "VirtualMachineScaleSets"
  }

  linux_profile {
    admin_username = "ubuntu"

    ssh_key {
      key_data = file(var.ssh_public_key)
    }
  }
  network_profile {
    network_plugin     = "kubenet"
    network_policy     = "calico"
    service_cidr       = "172.16.0.0/16"
    dns_service_ip     = "172.16.0.10"
    pod_cidr           = "172.18.0.0/16"
    docker_bridge_cidr = "172.17.0.1/16"
    outbound_type      = "userDefinedRouting"
    load_balancer_sku  = "standard"
  }
}

下一步,我把 terraform 文件拆成了两部分,aks 之前的 subnet,资源组,路由表作为一部分,先用 treaform 创建出来。然后 aks 的创建,回到以前的方式,使用 azure cli 方式,即 az aks create -n cftestAKS001 -g test-group --location eastus --network-plugin kubenet -- 等等一堆参数,结果还是一样的报错。这直接推翻了之前的理解,问题不在 terraform 定义的 aks 配置文件部分。而在于 subnet 或者 路由表。

我把 aks2的 subnet 和 路由表及授权信息,与 aks1 的subnet及路由表,在 azure portal 上进行了反复多次对比,并没有发现问题。现在虽然定位到了范围,但并没有找到根因。

所以还是回到了 aks 的关联资源去查看 Activity log,最终在 aks 的 node-resource-group 也就是自动创建出来的 MC_rg_xxx 那个资源组 Activity log 找到了一条关键信息。也就是总结里说的第三条。如果早点发现这条 log 就会少走很多弯路,要去关注相关的资源/资源组,因为对azure的每一次操作,都会在Activity log中留下记录,这也算是这次学到的一个很重要的点吧。

Activity log 中有一个操作 "write PrivateEndpoint" 状态为 Fail,查看这条 Fail 的JSON,不要查看子操作,子操作是start 记录,没有报错信息。

private endpoint 创建失败是因为 it has private endpoint network policies enabled

  "responseBody": "{\"error\":{\"code\":\"PrivateEndpointCannotBeCreatedInSubnetThatHasNetworkPoliciesEnabled\",\"message\":\"Private endpoint /subscriptions/xxxxx-xxxx-xxx/resourceGroups/MC_RG_xxxxxxxx/providers/Microsoft.Network/privateEndpoints/kube-apiserver cannot be created in a subnet /subscriptions/xxxxx-xxxxxx/resourceGroups/rg_xxxxxx/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/subnet2 since it has private endpoint network policies enabled.\",\"details\":[]}}",

通过命令查询,这次通过terraform新建的subnet2,值是enabled

~$ az network vnet subnet list --resource-group rg123--vnet-name vnet1 --query "[?name=='subnet2']" |grep -i privateEndpointNetworkPolicies
    "privateEndpointNetworkPolicies": "Enabled",

这是之前通过portal 创建的subnet1,值是disabled

~$ az network vnet subnet list --resource-group rg123 --vnet-name vnet1 --query "[?name=='subnet1']" |grep -i privateEndpointNetworkPolicies
    "privateEndpointNetworkPolicies": "Disabled",

在portal 再手动建一个subnet,确认下,确实如此

~$ az network vnet subnet list --resource-group rg123 --vnet-name vnet1 --query "[?name=='testsub']" |grep -i privateEndpointNetworkPolicies
    "privateEndpointNetworkPolicies": "Disabled",

修改 terraform main.tf 文件,在subnet加这一段
private_endpoint_network_policies_enabled = false

重新执行 terraform apply 成功创建aks

terraform 关于这个参数的说明:
https://github.com/hashicorp/terraform-provider-azurerm/blob/main/website/docs/r/subnet.html.markdown

private_endpoint_network_policies_enabled - (Optional) Enable or Disable network policies for the private endpoint on the subnet. Setting this to true will Enable the policy and setting this to false will Disable the policy. Defaults to true.

-> NOTE: Network policies, like network security groups (NSG), are not supported for Private Link Endpoints or Private Link Services. In order to deploy a Private Link Endpoint on a given subnet, you must set the private_endpoint_network_policies_enabled attribute to false. This setting is only applicable for the Private Link Endpoint, for all other resources in the subnet access is controlled based via the Network Security Group which can be configured using the azurerm_subnet_network_security_group_association resource.

同时还发现了另外一个通过 terraform 部署的差异,就是 k8s api 的域名。当 enable Private cluster 时,terraform 创建 k8s api 域名是这样的,带有 privatelink,是私网域名,无法在公网解析。
akseamobilesit02-hhjhanhy.75e5c9f7-ba13-4511-8a47-95b522e3fc38.privatelink.eastasia.azmk8s.io

而通过命令行创建 aks 时,enable Private cluster ,k8s 的api 地址是这样的 akseamobilesit02-mphslihq.hcp.eastasia.azmk8s.io ,不过也只是能解析到,是 vnet 内网地址,在公网是连不上的。也可以手动更新 aks 的配置 --enable-public-fqdn 来开启公网解析。

[root@centos8 private-aks]# nslookup akseamobilesit02-hhjhanhy.75e5c9f7-ba13-4511-8a47-95b522e3fc38.privatelink.eastasia.azmk8s.io
Server:         114.114.114.114
Address:        114.114.114.114#53

** server can't find akseamobilesit02-hhjhanhy.75e5c9f7-ba13-4511-8a47-95b522e3fc38.privatelink.eastasia.azmk8s.io: NXDOMAIN

[root@centos8 private-aks]# az aks update -g rg_ea_mobile_sit01 -n akseamobilesit02 --enable-public-fqdn

[root@centos8 private-aks]# nslookup akseamobilesit02-mphslihq.hcp.eastasia.azmk8s.io
Server:         114.114.114.114
Address:        114.114.114.114#53

Non-authoritative answer:
Name:   akseamobilesit02-mphslihq.hcp.eastasia.azmk8s.io
Address: 10.2.0.4

关于如何通过 terraform 创建一个专用 aks 集群提高安全性,可以参照之前的文章。
https://github.com/cai11745/hybrid-cloud/blob/master/terraform/2023-03-10-terraform-create-private-aks.md

参考文档

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
https://github.com/hashicorp/terraform-provider-azurerm/blob/main/website/docs/r/subnet.html.markdown

关注我的github,后续更新都会同步。
https://github.com/cai11745/hybrid-cloud

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容