【问题标题】:terraform output Google Kubernetes cluster inggress load balancer ipterraform 输出 Google Kubernetes 集群入口负载均衡器 ip
【发布时间】:2019-01-01 12:33:07
【问题描述】:

我已经成功地使用 terraform 自动化了 kubernetes 集群部署。在启动集群之后,terraform 还使用配置(使用 local-exec 运行 .sh 脚本)将我的应用程序部署到集群。我还在向集群添加入口,一旦创建,我需要获取入口负载均衡器 IP。更可取的选择是 terraform 输出。 我现在得到它的方式是在我的脚本末尾运行这部分代码

IP="$(kubectl get ingress appname --no-headers | awk '{print $3}')"
echo "Load Balancer IP $IP"

但是这个有问题,我需要在运行这个命令之前添加 sleep 以确保 IP 已经分配。而且我不能确定增加的睡眠时间是否足够。 实际上需要这样的东西,但对于我的入口负载均衡器 IP

output "google_container_cluster_endpoint" {
  value = "${google_container_cluster.k8s.endpoint}"
}

output "google_container_cluster_master_version" {
  value = "${google_container_cluster.k8s.master_version}"
}

【问题讨论】:

  • 您正在使用哪些 terraform 模块?您如何配置集群本身?
  • 我不使用任何模块,使用资源“google_container_cluster”创建 kubernetes 集群
  • 有一个Kubernetes provider 和一个匹配的kubernetes_service data source,但我认为没有强制 Terraform 等待负载均衡器存在的好方法。
  • output "IP" { value = ${kubernetes_service.load_balancer_service.load_balancer_ingress.0.ip}" } 这样的东西不起作用吗?

标签: kubernetes google-cloud-platform kubernetes-ingress


【解决方案1】:

我已经设法以完全声明的方式获取外部入口 IP。它基于不同的提供商,包括 azurerm、kubernetes、helm。我的目标是 Azure Kubernetes 服务,但解决方案与云无关。

解决方案说明:

在 ingress 创建后使用 kubernetes 提供程序连接集群。 Kubernetes 提供允许读取外部 ip 等服务数据。

供应商概览:

  • azurerm 提供程序用于 Azure 通信
    • 可以通过不同的提供商创建 Kubernetes (K8s),
  • helm 提供程序用于入口安装,
    • 可以使用不同的方法创建入口,
  • kubernetes 提供商允许我查询负载均衡器服务

短sn-p

provider "kubernetes" { }

provider "helm" { }

resource "helm_release" "nginx-ingress" {
  name             = "nginx-ingress"
  namespace        = "nginx-ingress"
  create_namespace = true
  repository       = "https://kubernetes-charts.storage.googleapis.com"
  chart            = "nginx-ingress"

  set {
    name  = "controller.replicaCount"
    value = "2"
  }
}

data "kubernetes_service" "service_ingress" {
  metadata {
    name      = "nginx-ingress-controller"
    namespace = "nginx-ingress"
  }

  depends_on = [ helm_release.nginx-ingress ] 
}

output "ip" {
  value = data.kubernetes_service.service_ingress.load_balancer_ingress.0.ip
}

完成sn-p

variable "subscription_id" {
  type = string
}

variable "client_id" {
  type = string
}

variable "client_secret" {
  type = string
}

variable "tenant_id" {
  type = string
}

variable "resource_location"{
  type = string
}

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "2.29.0"
    }

    kubernetes = {
      source = "hashicorp/kubernetes"
      version = "1.13.2"
    }

    helm = {
      source = "hashicorp/helm"
      version = "1.3.1"
    }
  }
}

provider "azurerm" {
  subscription_id = var.subscription_id
  client_id       = var.client_id
  client_secret   = var.client_secret
  tenant_id       = var.tenant_id
  features {}
}

provider "kubernetes" {
  load_config_file       = "false"
  host                   = azurerm_kubernetes_cluster.aks.kube_config.0.host
  client_certificate     = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.client_certificate)
  client_key             = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.client_key)
  cluster_ca_certificate = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.cluster_ca_certificate)
}

provider "helm" {
  kubernetes {
    load_config_file       = "false"
    host                   = azurerm_kubernetes_cluster.aks.kube_config.0.host
    client_certificate     = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.client_certificate)
    client_key             = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.client_key)
    cluster_ca_certificate = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.cluster_ca_certificate)
  }
}

data "kubernetes_service" "service_ingress" {
  metadata {
    name      = "nginx-ingress-controller"
    namespace = "nginx-ingress"
  }

  depends_on = [ helm_release.nginx-ingress ] 
}

resource "azurerm_resource_group" "rg" {
  name     = "myapp"
  location = var.resource_location
}

resource "azurerm_kubernetes_cluster" "aks" {
  name                = "myapp"
  location            = var.resource_location
  resource_group_name = azurerm_resource_group.rg.name
  dns_prefix          = "myapp"
  kubernetes_version  = "1.17.11"

  default_node_pool {
    name            = "default"
    node_count      = 2
    vm_size         = "Standard_B2s"
    os_disk_size_gb = 30
    type = "VirtualMachineScaleSets"
    enable_auto_scaling = false
  }

  service_principal {
    client_id     = var.client_id
    client_secret = var.client_secret
  }

  role_based_access_control {
    enabled = true
  }
}

resource "helm_release" "nginx-ingress" {
  name             = "nginx-ingress"
  namespace        = "nginx-ingress"
  create_namespace = true
  repository       = "https://kubernetes-charts.storage.googleapis.com"
  chart            = "nginx-ingress"

  set {
    name  = "controller.replicaCount"
    value = "2"
  }

  set {
    name  = "controller.nodeSelector.kubernetes\\.io/os"
    value = "linux"
  }

  set {
    name  = "defaultBackend.nodeSelector.kubernetes\\.io/os"
    value = "linux"
  }
}

output "ip" {
  value = data.kubernetes_service.service_ingress.load_balancer_ingress.0.ip
}

【讨论】:

  • 完美!我只需要将ip 输出修改为data.kubernetes_service.service_ingress.status[0].load_balancer[0].ingress[0].ip
  • 我也做了同样的事情,但是设置依赖项并不足以强制等待它的创建,tf 只是将它作为null 获取,所以第一个apply 失败了,并且第二个成功读取数据资源并输出值。恼人的。在对等待资源进行一些测试后,如果该值从一开始就不存在,则似乎根本不会读取该值。
  • 也许有一些变化,但解决方案完全可以运行。依赖性工作正常。有人有同样的问题吗?
  • 原因可能是 helm 中的行为发生了变化,因此在 nginx helm 资源中。 github.com/helm/helm/pull/7530
【解决方案2】:

在漫长的星期六之后,我终于找到了解决问题的办法。我遇到了几乎相同的问题,所以这是我的解决方案,肯定可以改进。

我分为两部分:

1.- 我将使用 local-exec 运行一个脚本,解决在负载 LoadBalancer 中等待有效 IP 的问题 2.-Terraform,使用外部数据源调用以json格式回答的“程序”。我的“程序”是一个抓取 IP 的 bash 脚本。结果,我在一个变量中有我想要的数据。

我这样做是因为我不知道如何使用 外部数据源 来调试问题,而且我遇到了“奇怪的事情”

首先我运行代码以等待有效的 IP。 Terraform 调用 local-exec


provisioner "local-exec" {
  command = "./public-ip.sh"
  interpreter = ["/bin/bash", "-c"]
}

这是我用过的脚本


#!/bin/bash
#public-ip.sh
#!/bin/bash
# Exit if any of the intermediate steps fail
set -e

function valid_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

########################
# Grab the Public IP   #
#######################
WaitingTime=0
HaveIP=NO

echo "Let's check that LoadBalancer IP..."
MyPublicIP=$(kubectl get services --all-namespaces| grep LoadBalancer | awk '{print $5}')
valid_ip $MyPublicIP && HaveIP="OK"

until [ "$HaveIP" = "OK" -o "$WaitingTime" -ge 30 ]; do
    echo "sleeeping...."
    sleep 10
    echo "Play it again Sam..."
    MyPublicIP=$(kubectl get services --all-namespaces| grep LoadBalancer | awk '{print $5}')
    #if valid_ip $MyPublicIP; then echo "We got the IP"; HaveIP=YES ;else stat='Still without IP'; fi
    #if valid_ip $MyPublicIP; then HaveIP="OK" ; fi
    valid_ip $MyPublicIP && HaveIP="OK"
    #if valid_ip $MyPublicIP; then HaveIP="OK" ; fi
    WaitingTime=$((WaitingTime+1))
    echo $WaitingTime
done
if [ "$HaveIP" = "OK" ]; then echo  An the public IP is... $MyPublicIP; else echo "WT_ has happened now!!!"; fi

在我知道我已经准备好 IP 之后。我只需要抓住它。请注意 depends_on 控制,一旦我的资源 (google_container_cluster.tests) 创建,我将获取我的数据,而不是在他想要的时候。测试一下。这很棘手......


data "external" "insights-public-ip" {
  program = ["sh", "test-jq.sh" ]
  depends_on = ["google_container_cluster.tests"]
}

output "insights-public-ip" {
  value = "${data.external.insights-public-ip.result}"
}

这是 test-jq.sh(测试原因是我第一次使用 :S),我调用的脚本以 json 格式打印数据。


#!/bin/bash
#test-jq.sh
set -e
MyPublicIP=$(kubectl get services --all-namespaces | grep insights | grep LoadBalancer | awk '{print $5}')
jq -n --arg foobaz "$MyPublicIP" '{"extvar":$foobaz}'

希望对您有所帮助。至少我已经解决了我的问题。

【讨论】:

  • 不错的一个。它不能解决我的问题,因为我想通过输出得到它的主要原因是不必运行 shell 脚本。我当前的配置还使用 shell 脚本来获取负载均衡器 IP。但是,如果您想将 shell 脚本的输出作为变量获取,无需使用外部数据,您可以使用 TF_VARNAME 从 shell 中定义 terraform 变量。
  • 另一种获取负载均衡器 IP 作为输出变量的方法是使用这个 terraform 模块 (github.com/sl1pm4t/terraform-provider-kubernetes) 将入口部署为单独的 terraform 资源,并获取负载均衡器 IP 地址作为其输出。但是,如果没有限制使用 shell 脚本,您的解决方法看起来也不错。
【解决方案3】:

这可以做到,以这种方式仅使用 kubectl:

#!/bin/bash

while true;
do
  kubectl get svc -n istio-system istio-ingressgateway -o jsonpath='{"{\"ip\": "}{"\""}{.status.loadBalancer.ingress[0].ip}{"\"}"}' | grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" >/dev/null

  if [[ $? -eq 0 ]]; then
      kubectl get svc -n istio-system istio-ingressgateway -o jsonpath='{"{\"ip\": "}{"\""}{.status.loadBalancer.ingress[0].ip}{"\"}"}'
      exit 0
  fi
done

现在您可以编写外部数据资源的脚本如下:

data "external" "external-public-ip" {
  program = ["sh", "get-ip.sh" ]
  depends_on = [kubernetes_service.foo]
}

output "external-public-ip" {
  value = "${data.external.external-public-ip.result}"
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 2022-01-03
    • 1970-01-01
    • 2020-10-23
    • 2018-10-24
    • 1970-01-01
    • 2017-03-01
    相关资源
    最近更新 更多