<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cloud &#8211; Johnny Morano&#039;s Tech Articles</title>
	<atom:link href="https://jmorano.moretrix.com/tag/cloud/feed/" rel="self" type="application/rss+xml" />
	<link>https://jmorano.moretrix.com</link>
	<description>Ramblings of an old-fashioned space cowboy</description>
	<lastBuildDate>Sun, 10 Apr 2022 09:38:22 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.2</generator>

<image>
	<url>https://jmorano.moretrix.com/wp-content/uploads/2022/04/cropped-jmorano_emblem-32x32.png</url>
	<title>Cloud &#8211; Johnny Morano&#039;s Tech Articles</title>
	<link>https://jmorano.moretrix.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using Ansible to finalize Hashicorp Packer images</title>
		<link>https://jmorano.moretrix.com/2022/04/using-ansible-to-finalize-hashicorp-packer-images/</link>
					<comments>https://jmorano.moretrix.com/2022/04/using-ansible-to-finalize-hashicorp-packer-images/#respond</comments>
		
		<dc:creator><![CDATA[Johnny Morano]]></dc:creator>
		<pubDate>Fri, 08 Apr 2022 09:23:30 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Hashicorp]]></category>
		<category><![CDATA[Packer]]></category>
		<guid isPermaLink="false">https://jmorano.moretrix.com/?p=1430</guid>

					<description><![CDATA[Ansible provides a more flexible way to fine-tune Hashicorp Packer images compared to cloud-init. Playbooks can be executed&#8230;]]></description>
										<content:encoded><![CDATA[
<p><a rel="noreferrer noopener" href="https://www.ansible.com/" data-type="URL" data-id="https://www.ansible.com/" target="_blank">Ansible</a> provides a more flexible way to fine-tune <a rel="noreferrer noopener" href="https://www.packer.io/" data-type="URL" data-id="https://www.packer.io/" target="_blank">Hashicorp Packer</a> images compared to <a rel="noreferrer noopener" href="https://cloudinit.readthedocs.io/en/latest/" data-type="URL" data-id="https://cloudinit.readthedocs.io/en/latest/" target="_blank">cloud-init</a>. Playbooks can be executed once the guest image building is ready and boots up for the first time. This allows to create different types of Packer images based on different playbooks.</p>



<p>In this article, Packer images will created for <a href="https://azure.microsoft.com/en-us/" data-type="URL" data-id="https://azure.microsoft.com/en-us/" target="_blank" rel="noreferrer noopener">Azure</a> using <a href="https://www.packer.io/plugins/builders/azure/arm" data-type="URL" data-id="https://www.packer.io/plugins/builders/azure/arm" target="_blank" rel="noreferrer noopener">azure-arm</a> build type. The images will use an <a href="https://ubuntu.com/" data-type="URL" data-id="https://ubuntu.com/" target="_blank" rel="noreferrer noopener">Ubuntu</a> image available on Azure, as base image.</p>



<p>Let&#8217;s consider the following head of a Packer <a rel="noreferrer noopener" href="https://www.packer.io/docs/templates" data-type="URL" data-id="https://www.packer.io/docs/templates" target="_blank">template</a> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{  
  "builders": [{
      "type": "azure-arm",

      "use_azure_cli_auth": true,
      "subscription_id": "{{ user `subscription_id` }}",

      "managed_image_resource_group_name": "{{user `resource_group`}}",
      "managed_image_name": "{{user `managed_image_name`}}",

      "os_type": "{{user `basevm_os_type`}}",
      "image_publisher": "{{user `basevm_publisher`}}",
      "image_offer": "{{user `basevm_offer`}}",
      "image_sku": "{{user `basevm_sku`}}",

      "virtual_network_name": "{{user `virtual_network_name`}}",
      "virtual_network_resource_group_name": "{{user `virtual_network_resource_group_name`}}",
      "virtual_network_subnet_name": "{{user `virtual_network_subnet_name`}}",

      "azure_tags": {
        "dept": "DevOps",
        "task": "My custom base image"
      },

      "location": "{{user `location`}}",
      "vm_size": "{{user `vm_size`}}",

      "os_disk_size_gb": "{{user `os_disk_size_gb`}}",

      "shared_image_gallery_destination": {
        "subscription": "{{ user `subscription_id` }}",
        "resource_group": "{{user `resource_group`}}",
        "gallery_name": "{{user `gallery_name`}}",
        "image_name": "{{user `base_image`}}",
        "image_version": "{{user `base_image_version`}}",
        "replication_regions": "{{user `replication_regions`}}"
      },
      "shared_image_gallery_timeout": "2h1m1s"
    }],
</pre>



<p>All the variables surrounded by <code>{{user `` }}</code> are template variables, and must be configured in a separate file, example <code>my_base_image_vars.json</code>, which will be included later-on when initiating the Packer <a href="https://www.packer.io/docs/commands/build" data-type="URL" data-id="https://www.packer.io/docs/commands/build" target="_blank" rel="noreferrer noopener">build</a> command. The final image will be stored in <a href="https://azure.microsoft.com/" data-type="URL" data-id="https://azure.microsoft.com/" target="_blank" rel="noreferrer noopener">Azure</a>, in a <a href="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries" data-type="URL" data-id="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries" target="_blank" rel="noreferrer noopener">Shared Image Gallery</a>.</p>



<p>Packer however allows to configure extra <a rel="noreferrer noopener" href="https://www.packer.io/docs/provisioners" data-type="URL" data-id="https://www.packer.io/docs/provisioners" target="_blank">provisioners</a>, which will be executed once the initial virtual machine has been created and before the final image will be created.</p>



<p>One of those provisioner types is the <a rel="noreferrer noopener" href="https://www.packer.io/plugins/provisioners/ansible/ansible-local" data-type="URL" data-id="https://www.packer.io/plugins/provisioners/ansible/ansible-local" target="_blank">ansible-local</a> type. This provisioner allows to execute Ansible playbooks (and roles) once the virtual machine is booted, directly on the guest machine.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    "provisioners": [
      {
        "type": "shell",
        "inline_shebang": "/bin/sh -x",
        "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'",
        "script": "presetup.sh"
      },
      {
        "type": "ansible-local",
        "playbook_file": "./ansible/default_setup.yml",
        "playbook_dir": "./ansible",
        "role_paths": ["./ansible/defaults"],
        "clean_staging_directory": true,
        "staging_directory": "/tmp/packer-provisioner-ansible-local",
        "extra_arguments" : [ "--extra-vars", "ansible_python_interpreter=/usr/bin/python3" ]
      },
</pre>



<p>The first provisioner called, is the <a rel="noreferrer noopener" href="https://www.packer.io/docs/provisioners/shell" data-type="URL" data-id="https://www.packer.io/docs/provisioners/shell" target="_blank">shell</a> provisioner. This provisioner will upload and execute the script <code>presetup.sh</code>. This script could for instance ensure that the Ansible package is already installed before the next provisioner is called.</p>



<p>The second provisioner is the <a rel="noreferrer noopener" href="https://www.packer.io/plugins/provisioners/ansible/ansible-local" data-type="URL" data-id="https://www.packer.io/plugins/provisioners/ansible/ansible-local" target="_blank">ansible-loca</a>l type. The provisioner requires some parameters that must be configured:</p>



<ul class="wp-block-list"><li><code>playbook_file</code>: the Ansible playbook which will be executed</li><li><code>playbook_dir</code>: the base directory of the Ansible playbooks, roles, static_files, &#8230;</li><li><code>role_paths</code>: the path of the role which will be called in playbook_file (when required)</li></ul>



<p>The above example will upload all files in the <code>./ansible</code> directory (parameter <code>playbook_dir</code>) to the new guest virtual machine, to the directory configured in <code>staging_directory</code>, and will call the Ansible playbook <code>default_setup.yml</code>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">---
- name: Default post installation
  hosts: all
  connection: local
  become: yes
  tasks:
    - name: Import the Microsoft signing key into apt
      apt_key:
        url: "https://packages.microsoft.com/keys/microsoft.asc"
        state: present

    - name: Add the Azure CLI software repository
      apt_repository:
        repo: "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ {{ansible_distribution_release}} main"
        filename: azure-cli
        state: present

  roles:
    - defaults
</pre>



<p>The above Ansible playbook use the parameter <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">connection: local</mark></code>. This is very important and must be included in each playbook executed by the ansible-local provisioner.</p>



<p>At first the playbook will execute two tasks which will ensure that the <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt" data-type="URL" data-id="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt" target="_blank" rel="noreferrer noopener">Microsoft Azure-CLI APT repository</a> is installed and properly set up.</p>



<p>Afterwards, it will call the <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">defaults</mark></code> Ansbile <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html" data-type="URL" data-id="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html" target="_blank" rel="noreferrer noopener">role</a>. This role is set up as a typical <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html" data-type="URL" data-id="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html" target="_blank" rel="noreferrer noopener">Ansible role</a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ansible/defaults:
tasks  templates  vars

ansible/defaults/tasks:
main.yml

ansible/defaults/templates:
modprobe_blacklist.j2  policy-rc.d.conf.j2  policy-rc.d.j2  securetty.j2  sysctl_base.j2

ansible/defaults/vars:
main.yml
</pre>



<p>The <code>main.yml</code> in the <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">tasks</mark></code> sub-directory is used to configure the required post installation steps.</p>



<p>Example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">---
- name: Ensure default packages
  apt:
    name: "{{ default_packages }}"
    state: latest

- name: Ensure latest version of all packages
  apt:
    upgrade: dist
    force_apt_get: yes
    dpkg_options: 'force-confold,force-confdef'
    autoremove: yes
    autoclean: yes

- name: Update python alternatives (for Log Analytics)
  shell: |
    update-alternatives --remove-all python
    update-alternatives --install /usr/bin/python python /usr/bin/python2 1

- name: Forward Syslog-NG logs to Log Analytics
  ansible.builtin.copy:
    src: static_files/syslog-ng-lad.conf
    dest: /etc/syslog-ng/conf.d/syslog-ng-lad.conf
    owner: root
    group: root
    mode: '0644'

...</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://jmorano.moretrix.com/2022/04/using-ansible-to-finalize-hashicorp-packer-images/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Terraform and libvirt nodes</title>
		<link>https://jmorano.moretrix.com/2022/03/terraform-and-libvirtd-nodes/</link>
					<comments>https://jmorano.moretrix.com/2022/03/terraform-and-libvirtd-nodes/#comments</comments>
		
		<dc:creator><![CDATA[Johnny Morano]]></dc:creator>
		<pubDate>Wed, 30 Mar 2022 09:45:11 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Hashicorp]]></category>
		<category><![CDATA[Hetzner]]></category>
		<category><![CDATA[KVM]]></category>
		<category><![CDATA[Libvirt]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Qemu]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://jmorano.moretrix.com/?p=1302</guid>

					<description><![CDATA[Libvirt (libvirtd) nodes (based on KVM and Qemu) are a great and cheap (read: free) alternative of deploying&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Libvirt (<a href="https://libvirt.org/manpages/libvirtd.html" data-type="URL" data-id="https://libvirt.org/manpages/libvirtd.html" target="_blank" rel="noreferrer noopener">libvirtd</a>) nodes (based on KVM and Qemu) are a great and cheap (read: free) alternative of deploying virtual nodes in a cloud. Required is a server which will act as a hypervisor, in our article we chose to use a <a href="https://www.hetzner.com/" data-type="URL" data-id="https://www.hetzner.com/" target="_blank" rel="noreferrer noopener">Hetzner</a> server installed with <a href="https://ubuntu.com/" data-type="URL" data-id="https://ubuntu.com/" target="_blank" rel="noreferrer noopener">Ubuntu Linux </a>20.4-lts.</p>



<p>After the default installation of Ubuntu 20.4-lts, the following packages are required to get started as a hypervisor:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="monokai" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">apt install qemu-kvm libvirt-daemon bridge-utils virtinst libvirt-daemon-system virt-top libguestfs-tools libosinfo-bin qemu-system virt-manager qemu pm-utils</pre>



<p>Once these are installed, the <code>vnet_hosts </code>module needs to be pre-loaded in <code>/etc/modules</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="monokai" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">echo vhost_net | tee -a /etc/modules
modprobe vhost_net</pre>



<p>The hypervisor is now ready to start creating and deploying virtual machines. </p>



<p>In this article, <a rel="noreferrer noopener" href="https://www.terraform.io/" data-type="URL" data-id="https://www.terraform.io/" target="_blank">Terraform</a> will be used to manage the virtual machines in libvirtd. All example code snippets are available on Github, under <a href="https://github.com/insani4c/terraform-libvirt" target="_blank" rel="noreferrer noopener">https://github.com/insani4c/terraform-libvirt</a></p>



<p>Terraform has an excellent provider (<a href="https://registry.terraform.io/providers/dmacvicar/libvirt/latest" data-type="URL" data-id="https://registry.terraform.io/providers/dmacvicar/libvirt/latest" target="_blank" rel="noreferrer noopener">dmacvicar/libvirtd</a>) to manage the libvirtd nodes, which needs to be loaded and initialized:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="monokai" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
    }
  }
}

provider "libvirt" {
  uri = "qemu+ssh://root@192.168.1.1/system"
}</pre>



<p>In the above code snippet, Terraform will ensure the libvirt provider is loaded and it is configured to connect to the host with IP address <code>192.168.1.1</code> as the root user (this requires that a SSH public key is installed on the remote server, of the user who will be executing Terraform).</p>



<p>Next, the network will defined, where the virtual nodes will be deployed in.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="monokai" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">resource "libvirt_network" "my_network" {
  name = "my_net"

  mode = "nat"

  addresses = ["10.1.2.0/24"]
  domain    = var.dns_domain

  autostart = true

  dhcp {
    enabled = false
  }

  dns {
    enabled = true

    local_only = false
    forwarders { address = "127.0.0.53" }

    hosts  {
        hostname = "host01"
        ip = "10.1.2.10"
      }
    hosts {
        hostname = "host02"
        ip = "10.1.2.20"
      }
  }  
}</pre>



<p>The above code will ensure that a network of type <code>NAT</code> (to allow internal IPs, reachable from the hypervisor only) with network mask <code>10.1.2.0/24</code>, will be created. It will ensure that <code>DHCP</code> is disabled and it will enable a <code>DNS</code> setup (the package <code>dnsmasq</code> must be installed) with two predefined hosts, <code>host01</code> and <code>host02</code>.</p>



<p>Up next is the definition of the storage pools and volumes required for the virtual machines.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="monokai" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">resource "libvirt_pool" "default" {
  name = "default"
  type = "dir"
  path = "/data/vms/cluster_storage"
}

resource "libvirt_volume" "local_install_image" {
  name   = var.local_install_image
  pool   = libvirt_pool.default.name
  source = var.os_img_url
  format = "qcow2"
}</pre>



<p>The above defines the <code>libvirt_pool</code>, which basically configures the path on-disk for storing all sorts of volumes. Next it defines a volume called &#8220;<code>local_install_image</code>&#8220;, which will be used to set up the virtual machine as the volume will contain the &#8220;cloud image&#8221; for the installation. This volume requires two variables:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="monokai" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">variable "os_img_url" {
  description = "URL to the OS image"
  default     = "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
}

variable "local_install_image" {
    description = "The name of the local install image"
    default     = "base-os-ubuntu-focal.qcow2"
}</pre>


]]></content:encoded>
					
					<wfw:commentRss>https://jmorano.moretrix.com/2022/03/terraform-and-libvirtd-nodes/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
