【问题标题】:How do I use the file provisioner with google_compute_instance_template?如何将文件配置器与 google_compute_instance_template 一起使用?
【发布时间】:2016-04-13 07:38:48
【问题描述】:

使用 Terraform,我需要将文件复制到 Google Compute Engine 实例模板。为此,我通常使用file provisioner,但它不起作用,因为它依赖于SSH connections,由于需要外部可访问的主机地址而失败。由于实例模板的动态特性,我不知道如何将外部可访问的主机地址分配给实例。

如何实现将文件复制到通过实例模板(通过 Terraform)创建的 GCE 实例?

示例 Terraform google_compute_instance_template 定义

resource "google_compute_instance_template" "node" {
  name = "kubernetes-node-template"
  machine_type = "g1-small"
  can_ip_forward = true
  tags = ["staging", "node"]

  network_interface {
    network = "default"
  }

  provisioner "file" {
    source = "worker/assets/kubelet.service"
    destination = "/etc/systemd/system/kubelet.service"
  }

  connection {
    user = "core"
    type = "ssh"
    private_key = "${file("~/.ssh/id_rsa")}"
  }
}

【问题讨论】:

  • 我正要添加完全相同的问题。我有几乎相同的配置,它不会导致错误,但不会传输文件。您是否在此尝试中收到任何错误?
  • @Adron 我记得它无法获取 SSH 连接并出现明显错误,是的。
  • 啊,我能够使连接(至少没有出现错误)工作,但它实际上并没有传输我为源设置的文件。我确实必须设置 gcloud ~/.ssh/google_compute_engine 密钥(使用 gcloud init 进行设置并尝试建立您的第一个连接,然后它会要求您根据 cli 需要密钥的方式设置 ssh 密钥。)一旦我设置了 gcloud 密钥并将其添加到连接 private_key 值,错误就消失了,所以我假设它已连接。我现在的问题是实际上没有任何文件副本发生。
  • @Adron 对我来说失败并出现以下错误:* dial tcp :22: getsockopt: connection refused
  • 据我了解,实例模板实际上无法连接或配置文件或脚本,因为它们不是运行机器,只有模板。可能最好使用文件构建映像或在实例从模板启动时配置它们

标签: ssh google-compute-engine terraform


【解决方案1】:

我能够通过以下配置解决此问题。

resource "google_compute_instance" "hubmud" {
    name = "hubmud"
    machine_type = "f1-micro"

    tags = ["buildserver", "jenkins", "central", "terraformer"]
    tags = [ "http-server" ]

    zone = "us-central1-b"

    disk {
        image = "ubuntu-1404-trusty-v20160406"
    }

    network_interface {
        network = "default"
        access_config {}
    }

    provisioner "file" {
        source = "installations.sh"
        destination = "installations.sh"
        connection {
            type = "ssh"
            user = "ubuntu"
            private_key = "${file("~/.ssh/google_compute_engine")}"
        }
    }

    provisioner "remote-exec" {
        inline = [
          "chmod +x ~/installations.sh",
          "cd ~",
          "./installations.sh"
        ]
        connection {
            type = "ssh"
            user = "ubuntu"
            private_key = "${file("~/.ssh/google_compute_engine")}"
        }

    }

    service_account {
        scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
}

我使用的 SSH 密钥是由 gcloud 实例生成的,要复制的文件必须采用所示格式。我确实遇到了使用~/ 或仅./ 来指定文件位置的问题。还需要注意的是,在“ubuntu”帐户下复制的文件,这似乎是 GCE 在图像上默认拥有的 ubuntu 上的默认帐户。

请注意,我还添加了type = "ssh",尽管这是连接类型的默认值,因此不需要它。不过我喜欢在我的配置文件中详细说明一些内容,所以我添加了它。

【讨论】:

  • 我认为这个问题的一个关键部分是作者希望提供一个实例模板,而不是一个普通的实例。在您的解决方案中应明确指出这种差异
  • connection { 闭包(包括类型、用户和 private_key)解决了这个问题。
【解决方案2】:

您可以通过 SSH 连接到 google_compute_instance(毕竟这是一个具体的、有形的 VM),但既不能连接到 google_compute_instance_group_manager,也不能连接到 google_compute_instance_template 因为这些是抽象的。

https://github.com/terraform-providers/terraform-provider-google/issues/52 中所述,目前这是不可能的。

【讨论】:

    【解决方案3】:

    也许这个功能是后来添加的,但从 2021 年初开始,您可以使用 google_compute_instance_template 的可选 metadata_startup_script 参数来指定一个脚本,该脚本将在每次从模板创建的任何实例启动时运行:

    resource "google_compute_instance" "hubmud" {
        name = "hubmud"
        machine_type = "f1-micro"
    
        tags = ["buildserver", "jenkins", "central", "terraformer"]
        tags = [ "http-server" ]
    
        zone = "us-central1-b"
    
        disk {
            image = "ubuntu-1404-trusty-v20160406"
        }
    
        network_interface {
            network = "default"
            access_config {}
        }
    
        # As per the documentation for google_compute_instance_template (https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_instance_template#metadata_startup_script)
        # you can set either metadata.startup-script or metadata_startup_script
        # to the contents of a file that will be added to the metadata of
        # any instance created from the template. 
        # In both cases the script will run each time the instance starts. 
        # The difference is that if metadata_startup_script is used and the metadata 
        # value is changed the instance will be destroyed and recreated before 
        # running the new script.
        metadata_startup_script = file("${path.module}/installations.sh")
    
        service_account {
            scopes = ["userinfo-email", "compute-ro", "storage-ro"]
        }
    }
    

    请注意,此机制需要操作系统支持,但正如 the documentation for the underlying arguments on google_compute_instance 指出的那样:

    “大多数基于 linux 的映像将在每次启动时在 shell 中运行 metadata.startup-script 的内容。至少,Debian、CentOS、RHEL、SLES、Container-Optimized OS 和 Ubuntu 映像支持此键。 Windows 实例需要其他键,具体取决于脚本的格式和您希望它运行的时间。”

    早在 Ubuntu 16.04 就进行了测试,该版本于本月底达到 LTS 的 EOL。所以这个功能已经存在了 5 年多。不清楚它是否在很久以前就被 GCP Terraform 提供者公开了,但它现在可以正常工作了。

    【讨论】:

      【解决方案4】:

      当您第一次启动您的实例时,您可以将元数据用于运行脚本和其他任何操作,但它只能运行一次。对于重播,元数据需要重新创建实例。

      metadata = {
          startup-script = "echo LOL SSH CONNECTION > /test.info"
      }
      
      OR
      
      metadata = {
          startup-script = "${file("${path.module}/shared/runner/bootstrap.sh")}"
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-23
        • 1970-01-01
        • 2014-09-08
        • 2019-01-11
        • 2015-12-10
        • 2019-06-08
        相关资源
        最近更新 更多