首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Terraform中检测可能的更改并执行它们

在Terraform中检测可能的更改并执行它们
EN

Stack Overflow用户
提问于 2019-06-04 04:51:39
回答 3查看 1.2K关注 0票数 2

我想把Ansible和Terraform结合起来,这样Terraform就可以创建机器,Ansible就可以配置它们了。使用terraform-provisioner-ansible可以将它们无缝地结合在一起。但我发现Ansible缺乏变化检测,这在Ansible独立运行时是不会发生的。

TL;DR:如何将Ansible中所做的更改应用于Terraform Ansible插件?或者至少在每次更新时执行ansible插件,这样Ansible就可以自己处理了?

示例用例

考虑下面的攻略,它安装了一些软件包

代码语言:javascript
复制
- name: Ansible install package test
  hosts: all
  tasks: 
  - name: Install cli tools
    become: yes
    apt:
      name: "{{ tools }}"
      update_cache: yes
    vars:
      tools:
        - nnn
        - htop

使用插件将其集成到Terraform中

代码语言:javascript
复制
resource "libvirt_domain" "ubuntu18" {
  # ...
  connection {
    type = "ssh"
    host = "192.168.2.2"
    user = "ubuntu"
    private_key = "${file("~/.ssh/id_rsa")}"
  }
  provisioner "ansible" {
    plays {
      enabled = true
      become_method = "sudo"

      playbook = {
        file_path = "ansible-test.yml" 
      }
    }
  }
}

在第一次运行时,fork会很好。但后来我发现有个包裹不见了

代码语言:javascript
复制
- name: Ansible install package test
  hosts: all
  tasks: 
  - name: Install cli tools
    become: yes
    apt:
      name: "{{ tools }}"
      update_cache: yes
    vars:
      tools:
        - nnn
        - htop
        - vim # This is a new package

当运行terraform plan时,我将获得No changes. Infrastructure is up-to-date.,我的新包vim将永远不会安装!所以Ansible没有运行,因为如果Ansible运行,它将安装新的包。

问题似乎出在the provisioner itself

创建时置备程序仅在创建期间运行,而不会在更新期间或任何其他生命周期中运行。它们是用来执行系统引导的一种方法。

但是应用更新的正确方式是什么呢?我尝试了一个带有depends_on链接的null_ressource到我的vm资源,但是Terraform也没有检测到Ansible部分的变化。似乎是来自Terraform插件的lack of change detection

在文件里我只找到了销毁时间的预设者。但没有更新。我可以摧毁并重新创造机器。这会让事情变慢很多。我喜欢Ansible的方法,即检查呈现的内容,并只应用尚未呈现的更改,这似乎是一种很好的配置方式。

有没有可能用Terraform做类似的事情?

以我目前的经验( Ansible比Terraform更多),我没有看到任何其他方法,就是放弃优秀的插件,自己执行Ansible。但这也会丢弃很好的集成。因此,我需要自己生成清单文件,或者甚至手动生成清单文件(在我看来,这缺少自动化方法)。

source_code_hash可能是一种选择,但不灵活:当有多个角色/角色时,我需要为每个容易出错的文件手动执行此操作。

EN

回答 3

Stack Overflow用户

发布于 2019-06-04 17:44:38

使用带有伪触发器的null_ressource

来自tedsmitt的想法使用时间戳作为触发器,这似乎是强制配置器的唯一方法。但是,从命令行界面直接运行ansible-playbook会增加手动维护清单的开销。您不能从此处调用python dynamic inventory script,因为terraform apply需要在

在我看来,更好的方法是在这里运行ansible provisioner

代码语言:javascript
复制
resource "null_resource" "ansible-provisioner" {
  triggers {
      build_number = "${timestamp()}"
  }
  depends_on = ["libvirt_domain.ubuntu18"]

  connection {
    type = "ssh"
    host = "192.168.2.2"
    user = "ubuntu"
    private_key = "${file("~/.ssh/id_rsa")}"
  }
  provisioner "ansible" {
    plays {
      enabled = true
      become_method = "sudo"

      playbook = {
        file_path = "ansible-test.yml" 
      }
    }
  }
}

唯一的问题是: Terraform每次都会识别一个伪变化

代码语言:javascript
复制
Terraform will perform the following actions:

-/+ null_resource.ansible-provisioner (new resource required)
      id:                    "3365240528326363062" => <computed> (forces new resource)
      triggers.%:            "1" => "1"
      triggers.build_number: "2019-06-04T09:32:27Z" => "2019-06-04T09:34:17Z" (forces new resource)


Plan: 1 to add, 0 to change, 1 to destroy.

根据其他可用的解决方案,这对我来说似乎是最好的折衷办法。

使用动态库存手动运行Ansible

我找到的另一种方式是dynamic inventory plugin,详细描述可以在in this blog entry中找到。它集成到Terraform中,并允许您将资源指定为库存主机,例如:

代码语言:javascript
复制
resource "ansible_host" "k8s" {
  inventory_hostname = "192.168.2.2"
  groups             = ["test"]
  vars = {
    ansible_user = "ubuntu"
    ansible_ssh_private_key_file = "~/.ssh/id_rsa"
  }
}

Python脚本使用此信息生成动态清单,可按如下方式使用:

代码语言:javascript
复制
ansible-playbook -i /etc/ansible/terraform.py ansible-test.yml

一个很大的好处是:它使您的配置保持干燥。Terraform拥有领先的配置文件,不需要同时维护单独的Ansible文件。以及使用变量的能力(例如,清单主机名不应该像我的示例中那样针对生产使用进行硬编码)。

在我的用例(Provision Rancher testcluster)中,null_ressource方法似乎更好一些,因为所有东西都是用一个Terraform命令构建的。不需要额外执行Ansible。但是根据需求,让Ansible保持一个单独的步骤可能会更好,所以我把这个作为替代。

安装插件

在尝试此解决方案时,请记住您需要从here安装相应的Terraform插件:

代码语言:javascript
复制
version=0.0.4
wget https://github.com/nbering/terraform-provider-ansible/releases/download/v${version}/terraform-provider-ansible-linux_amd64.zip -O terraform-provisioner-ansible.zip
unzip terraform-provisioner-ansible.zip
chmod +x linux_amd64/*
mv linux_amd64 ~/.terraform.d/plugins

还要注意,需要先删除automated provisioner from the solution above,因为它具有相同的名称(可能会发生冲突)。

票数 2
EN

Stack Overflow用户

发布于 2019-06-04 05:33:05

正如你在问题中提到的,插件中没有变化检测。您可以在null_resource上实现触发器,这样它就可以在每次应用时运行。

代码语言:javascript
复制
resource "null_resource" "ansible-provisioner" {
  triggers {
      build_number = "${timestamp()}"
  }
  provisioner "local-exec" {
    command = "ansible-playbook ansible-test.yml"
  }
}
票数 0
EN

Stack Overflow用户

发布于 2020-02-25 19:37:19

你可以试试这个,它对我很有效。

代码语言:javascript
复制
resource "null_resource" "ansible-swarm-setup" {
  local_file.ansible_inventory ]
  #nhu
  triggers= {
      instance_ids = join(",",openstack_compute_instance_v2.swarm-cluster-hosts[*].id)
  }
  connection {
    type = "ssh"
    user = var.ansible_user
    timeout = "3m"
    private_key = var.private_ssh_key
    host = local.cluster_ips[0]
  }
}

当它检测到实例索引/ it的变化时,它将触发ansible playbook。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56434398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档