In the continuing spirit of Terraforming all things, when I started to look into Ansible I wanted a way to have the base Control Node installed in a repeatable and consistent way. The setup and configuration of Ansible can be tricky and what I learnt in configuring the Ansible Control Node is that there can be a few dependencies that need to be in sync to line everything up. I also wanted to include some other modules and dependancies specifically related to the work that i’ll be doing with Windows Servers.
Requirements:
CentOS Template prepared and ready for deployment form vCenter – see example configuration http://everything-virtual.com/2016/05/06/creating-a-centos-7-2-vmware-gold-template/
The Terraform templates included in this repository requires Terraform to be available locally on the machine running the templates. Before you begin, please verify that you have the following information:
- Download Terraform (tested version 0.12.07) binary to your workstation.
- Terraform vSphere Provider
- Gather the VMware credentials required to communicate to vCenter
- Update the variable values in the
terraform.tfvars
file. - Update the resource values in the
main.tf
file.
I borrowed some of the steps off Markus Kraus’s great work around configuring his Ansible Development environment. But also had to work against some complications that I had working with my CentOS 7 VMware Template due to Python 2.7x being the default version that comes with that distribution build. I also included the modules for Kerberos authentication when working with Windows Servers connected to Active Directory Domains.
While it wasn’t directly impacting the Playbook’s I was running, I was getting the following warning while running NTLM or Kerberos authentication against any Windows server:
Given that Python 2.7 was set to be unsupported early next year, I was determined to have Ansible running off Python3. The combination and order of Linux packages and dependencies to get that working wasn’t straight forward and as you can see below in the main VM Terraform resource declaration, there are a lot of commands to make that happen.
Terraform Breakdown:
1 2 3 4 5 6 7 8 9 10 11 |
+---deploy_ansible_CentOS | | anisible-control-vm.tf | configure.sh | configure2.sh | main.tf | output.tf | README.md | terraform.tfvars | variables.tf | versions.tf |
There isn’t a lot to the Terraform code, other than deploying a cloned CentOS 7 Virtual Machine with the configured network setup via the Terraform Guest Customizations. Once the VM has been deployed and configured, the initial package deployment takes place…there are then two seperate configuration scripts which are uploaded and executed via SSH via the remote-exec blocks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
#=============================================================================== # vSphere Resources #=============================================================================== # Create a vSphere VM in the folder # resource "vsphere_virtual_machine" "TPM03-ANSIBLE-01" { # VM placement # name = var.vsphere_vm_name resource_pool_id = data.vsphere_resource_pool.resource_pool.id datastore_id = data.vsphere_datastore.datastore.id folder = var.vsphere_vm_folder tags = [data.vsphere_tag.tag.id] # VM resources # num_cpus = var.vsphere_vcpu_number memory = var.vsphere_memory_size # Guest OS # guest_id = data.vsphere_virtual_machine.template.guest_id # VM storage # disk { label = "${var.vsphere_vm_name}.vmdk" size = data.vsphere_virtual_machine.template.disks[0].size thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned eagerly_scrub = data.vsphere_virtual_machine.template.disks[0].eagerly_scrub } # VM networking # network_interface { network_id = data.vsphere_network.network.id adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0] } # Customization of the VM # clone { template_uuid = data.vsphere_virtual_machine.template.id customize { linux_options { host_name = var.vsphere_vm_name domain = var.vsphere_domain #time_zone = "${var.vsphere_time_zone}" } network_interface { ipv4_address = var.vsphere_ipv4_address ipv4_netmask = var.vsphere_ipv4_netmask } ipv4_gateway = var.vsphere_ipv4_gateway dns_server_list = [var.vsphere_dns_servers] dns_suffix_list = [var.vsphere_domain] } } #Update CentOS and Prep Modules for Ansible # provisioner "file" { source = "configure.sh" destination = "/tmp/configure.sh" connection { host = self.default_ip_address type = "ssh" user = "root" password = var.vsphere_vm_password } } provisioner "remote-exec" { inline = [ "chmod +x /tmp/configure.sh", "/tmp/configure.sh", "logout", ] on_failure = "continue" connection { host = self.default_ip_address type = "ssh" user = "root" password = var.vsphere_vm_password } } #Install Extras for Windows, PowerShell and VMware Management provisioner "file" { source = "configure2.sh" destination = "/tmp/configure2.sh" connection { host = self.default_ip_address type = "ssh" user = "root" password = var.vsphere_vm_password } } provisioner "remote-exec" { inline = [ "chmod +x /tmp/configure2.sh", "bash -x /tmp/configure2.sh", "exit", ] connection { host = self.default_ip_address type = "ssh" user = "root" password = var.vsphere_vm_password } } #Install PIP, WinRM and Ansible provisioner "remote-exec" { inline = [ "python3 -m pip install --upgrade --force-reinstall pip", "pip3 install pyvmomi", "pip3 install pywinrm", "pip3 install pywinrm>=0.3.0", "pip3 install --ignore-installed pywinrm>=0.3.0", "python3 -m pip install --upgrade pip", "pip3 install ansible", "ansible --version", ] connection { host = self.default_ip_address type = "ssh" user = "root" password = var.vsphere_vm_password } } } |
The last remote-exec block is the list of commands that works to install Ansible with PIP and using Phython3.
1 2 3 4 5 6 7 8 9 10 11 12 |
#Install PIP, WinRM and Ansible provisioner "remote-exec" { inline = [ "python3 -m pip install --upgrade --force-reinstall pip", "pip3 install pyvmomi", "pip3 install pywinrm", "pip3 install pywinrm>=0.3.0", "pip3 install --ignore-installed pywinrm>=0.3.0", "python3 -m pip install --upgrade pip", "pip3 install ansible", "ansible --version", ] |
The final command of the Terraform Plan execution is to list the installed Ansible version.
End to end the deployment takes about 7-8 minutes depending on your storage… Once done we have a fully functional Ansible Control Node ready for automation goodness!
This might seem like a little chicken or the egg… but Terraform and Ansible represent both sides of the IaC spectrum. As I mention in the README.md … time to try work out this Ansible thing out a little more!
References: