我想把Ansible和Terraform结合起来,这样Terraform就可以创建机器,Ansible就可以配置它们了。使用terraform-provisioner-ansible可以将它们无缝地结合在一起。但我发现Ansible缺乏变化检测,这在Ansible独立运行时是不会发生的。
TL;DR:如何将Ansible中所做的更改应用于Terraform Ansible插件?或者至少在每次更新时执行ansible插件,这样Ansible就可以自己处理了?
示例用例
考虑下面的攻略,它安装了一些软件包
- 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中
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会很好。但后来我发现有个包裹不见了
- 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可能是一种选择,但不灵活:当有多个角色/角色时,我需要为每个容易出错的文件手动执行此操作。
发布于 2019-06-04 17:44:38
使用带有伪触发器的null_ressource
来自tedsmitt的想法使用时间戳作为触发器,这似乎是强制配置器的唯一方法。但是,从命令行界面直接运行ansible-playbook
会增加手动维护清单的开销。您不能从此处调用python dynamic inventory script,因为terraform apply
需要在
在我看来,更好的方法是在这里运行ansible provisioner:
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每次都会识别一个伪变化
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中,并允许您将资源指定为库存主机,例如:
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脚本使用此信息生成动态清单,可按如下方式使用:
ansible-playbook -i /etc/ansible/terraform.py ansible-test.yml
一个很大的好处是:它使您的配置保持干燥。Terraform拥有领先的配置文件,不需要同时维护单独的Ansible文件。以及使用变量的能力(例如,清单主机名不应该像我的示例中那样针对生产使用进行硬编码)。
在我的用例(Provision Rancher testcluster)中,null_ressource
方法似乎更好一些,因为所有东西都是用一个Terraform命令构建的。不需要额外执行Ansible。但是根据需求,让Ansible保持一个单独的步骤可能会更好,所以我把这个作为替代。
安装插件
在尝试此解决方案时,请记住您需要从here安装相应的Terraform插件:
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,因为它具有相同的名称(可能会发生冲突)。
发布于 2019-06-04 05:33:05
正如你在问题中提到的,插件中没有变化检测。您可以在null_resource上实现触发器,这样它就可以在每次应用时运行。
resource "null_resource" "ansible-provisioner" {
triggers {
build_number = "${timestamp()}"
}
provisioner "local-exec" {
command = "ansible-playbook ansible-test.yml"
}
}
发布于 2020-02-25 19:37:19
你可以试试这个,它对我很有效。
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。
https://stackoverflow.com/questions/56434398
复制相似问题