Tag: vagrant

  • Quick Ansible control node with Vagrant

    Ansible is an IT automation tools which can configure systems, deploy files and software and orchestrate almost every possible task you can imagine.

    Unlike other configuration management tools like Chef or Puppet, Ansible is agent-less, and does all its magic over SSH. Forget about keeping up client daemons updated and additional certificates. Just use your existing SSH keys, or usernames and passwords.

    Due to it agent-less nature, we just need a host to initiate SSH sessions towards the managed hosts. This node is called a control node in the Ansible jargon.

    On this post, we’ll catch up with the basics of Vagrant and Ansible. The repository for this post is on https://github.com/baldoarturo/ansible-control-node.

    Download VirtualBox

    VirtualBox is a general-purpose full virtualizer for x86 hardware, targeted at server, desktop and embedded use. Get it from here.

    Get Vagrant

    We’ll use Vagrant to quickly spin up a control node, based on a ubuntu/xenial64 box. If you are not familiar with Vagrant, you just need to know it is a tool capable to provision VMs on different hypervisors, using a Vagrantfile a VM template.

    First, get Vagrant for your system here, https://www.vagrantup.com/downloads.html, and install it.

    Use Git

    In order to make everything easier, we’ll init a new git repository to keep track of all the configuration changes. Also, we can push this repository to a remote and clone from wherever we need it, making a portable Ansible control node.

    C:\Users\Arturo\Desktop\ansible-control-node>git init
    Initialized empty Git repository in C:/Users/Arturo/Desktop/ansible-control-node/.git/
    
    C:\Users\Arturo\Desktop\ansible-control-node>git config user.name "Arturo Baldo"
    
    C:\Users\Arturo\Desktop\ansible-control-node>git config user.email "[email protected]"
    
    C:\Users\Arturo\Desktop\ansible-control-node>

    Although everything can be done from a shell, I prefer to use the integrated terminal on VSCode, and make use of the universe of plugins. There is support for Ansible and Ansible Playbooks, Vagrant, a lot more!

    Also, even if this post uses a Windows system, everything is reproducible on Linux platforms because all the tools are multiplatform.

    Init the Vagrant environment

    The Vagrant CLI is self explanatory and easy to understand.

    C:\Users\Arturo\Desktop\ansible-control-node>vagrant
    Usage: vagrant [options] <command> [<args>]
    
        -v, --version                    Print the version and exit.
        -h, --help                       Print this help.
    
    Common commands:
         box             manages boxes: installation, removal, etc.
         cloud           manages everything related to Vagrant Cloud
         destroy         stops and deletes all traces of the vagrant machine
         global-status   outputs status Vagrant environments for this user
         halt            stops the vagrant machine
         help            shows the help for a subcommand
         init            initializes a new Vagrant environment by creating a Vagrantfile
         login
         package         packages a running vagrant environment into a box
         plugin          manages plugins: install, uninstall, update, etc.
         port            displays information about guest port mappings
         powershell      connects to machine via powershell remoting
         provision       provisions the vagrant machine
         push            deploys code in this environment to a configured destination
         rdp             connects to machine via RDP
         reload          restarts vagrant machine, loads new Vagrantfile configuration
         resume          resume a suspended vagrant machine
         snapshot        manages snapshots: saving, restoring, etc.
         ssh             connects to machine via SSH
         ssh-config      outputs OpenSSH valid configuration to connect to the machine
         status          outputs status of the vagrant machine
         suspend         suspends the machine
         up              starts and provisions the vagrant environment
         upload          upload to machine via communicator
         validate        validates the Vagrantfile
         version         prints current and latest Vagrant version
         winrm           executes commands on a machine via WinRM
         winrm-config    outputs WinRM configuration to connect to the machine

    First, run vagrant intit to initialize a new environment.

    C:\Users\Arturo\Desktop\ansible-control-node>vagrant init
    A `Vagrantfile` has been placed in this directory. You are now
    ready to `vagrant up` your first virtual environment! Please read
    the comments in the Vagrantfile as well as documentation on
    `vagrantup.com` for more information on using Vagrant.

    Wait! You have a new file on your git repository. Make it the first commit.

    C:\Users\Arturo\Desktop\ansible-control-node>git add .
    
    C:\Users\Arturo\Desktop\ansible-control-node>git commit -m "First commit"
    [master (root-commit) 1416f75] First commit
     1 file changed, 70 insertions(+)
     create mode 100644 Vagrantfile
    
    C:\Users\Arturo\Desktop\ansible-control-node>

    On the newly create Vagrantfile, we can set configuration and provisioning options for the VM.

    First, replace config.vm.box = "base" with config.vm.box = "ubuntu/xenial64" to use this box.

    If you want to see the VM, config vb.gui = true. By default this setting is commented out, so the VM will start in headless mode.

    Feel free to customize the VM memory by commenting out the vb.memory = "1024" setting and adjusting it to your needs.

    Once you are done, save your changes, commit, execute vagrant up, and watch Vagrant create a brand new VM for you.

    C:\Users\Arturo\Desktop\ansible-control-node>vagrant up
    Bringing machine 'default' up with 'virtualbox' provider...
    ==> default: Importing base box 'ubuntu/xenial64'...
    ==> default: Matching MAC address for NAT networking...
    ==> default: Checking if box 'ubuntu/xenial64' version '20191114.0.0' is up to date...
    ==> default: Setting the name of the VM: ansible-control-node_default_1574353915423_60685
    ==> default: Clearing any previously set network interfaces...
    ==> default: Preparing network interfaces based on configuration...
        default: Adapter 1: nat
    ==> default: Forwarding ports...
        default: 22 (guest) => 2222 (host) (adapter 1)
    ==> default: Running 'pre-boot' VM customizations...
    ==> default: Booting VM...
    ==> default: Waiting for machine to boot. This may take a few minutes...
        default: SSH address: 127.0.0.1:2222
        default: SSH username: vagrant
        default: SSH auth method: private key
        default: Warning: Connection reset. Retrying...
        default: Warning: Connection aborted. Retrying...
        default: Warning: Remote connection disconnect. Retrying...
        default: 
        default: Vagrant insecure key detected. Vagrant will automatically replace
        default: this with a newly generated keypair for better security.
        default: 
        default: Inserting generated public key within guest...
        default: Removing insecure key from the guest if it's present...
        default: Key inserted! Disconnecting and reconnecting using new SSH key...
    ==> default: Machine booted and ready!
    ==> default: Checking for guest additions in VM...
        default: The guest additions on this VM do not match the installed version of
        default: VirtualBox! In most cases this is fine, but in rare cases it can
        default: prevent things such as shared folders from working properly. If you see
        default: shared folder errors, please make sure the guest additions within the
        default: virtual machine match the version of VirtualBox you have installed on
        default: your host and reload your VM.
        default:
        default: Guest Additions Version: 5.1.38
        default: VirtualBox Version: 6.0
    ==> default: Mounting shared folders...
        default: /vagrant => C:/Users/Arturo/Desktop/ansible-control-node

    Well, how do we login into the new VM? Try vagrant ssh

    C:\Users\Arturo\Desktop\ansible-control-node>vagrant ssh
    Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-169-generic x86_64)
    
     * Documentation:  https://help.ubuntu.com
     * Management:     https://landscape.canonical.com
     * Support:        https://ubuntu.com/advantage
    
    
    0 packages can be updated.
    0 updates are security updates.
    
    New release '18.04.3 LTS' available.
    Run 'do-release-upgrade' to upgrade to it.
    
    
    vagrant@ubuntu-xenial:~$ whoami
    vagrant
    vagrant@ubuntu-xenial:~$ 

    Type exit and you will return to your system prompt.

    You’ll see that you have new items on your directory. A .log file, with the output from Vagrant, and a .vagrant/ directory.

    To exclude them from the repository, create a .gitignore, with the following contents.

    .vagrant/
    *.log

    Save and commit.

    Provisioning the VM

    Return to the Vagrantfile, and add a section like this:

      config.vm.provision "shell", inline: <<-SHELL
        apt-get update
        apt-get install software-properties-common -y
        apt-add-repository --yes --update ppa:ansible/ansible
        apt-get install ansible -y
      SHELL

    This block instructs Vagrant to execute commands on the shell. First, the package list is updated, then the software-properties-common package is installed. To install Ansible, the ppa:ansible/ansible repository is added, and then Ansible is installed.

    Notice the usage of -y to avoid interactive prompts.

    Save the file, commit, and run vagrant provision. This will re-provision the VM with the new instructions from the Vagrantfile.

    Once Vagrant finishes, connect once again with vagrant ssh, and run ansible --version.

    vagrant@ubuntu-xenial:~$ ansible --version
    ansible 2.9.1
      config file = /etc/ansible/ansible.cfg
      configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
      ansible python module location = /usr/lib/python2.7/dist-packages/ansible
      executable location = /usr/bin/ansible
      python version = 2.7.12 (default, Oct  8 2019, 14:14:10) [GCC 5.4.0 20160609]

    That’s great! We have just installed Ansible on our new VM.

    Seek and Destroy

    You might wonder, where is this VM? Head to the VirtualBox Manager, and you’ll find it inside.

    Here it is!

    Without asking anyone.. kill the machine and delete it.

    Hard power off
    Delete all files

    Head back to the console, and you will see that the SSH session has died. Of course, this makes perfect sense as the VM no longer exists.

    vagrant@ubuntu-xenial:~$ Connection to 127.0.0.1 closed by remote host.
     Connection to 127.0.0.1 closed.

    If you try to run vagrant provision, it will fail, as there is no VM to provision.

    C:\Users\Arturo\Desktop\ansible-control-node>vagrant provision
    ==> default: VM not created. Moving on...

    But what happens if you run vagrant up once again? Surprise! The VM will be recreated with all the previous configuration settings.

    Using Ansible

    Well, the VM is ready, Ansible is installed.. now what? Let’s write an inventory file and see what can we do.

    I’ll create a simple file to connect to a testing docker instance on 192.168.85.253. No need to worry about ssh keys now, as we are testing, username and password will do the trick.

    vagrant@ubuntu-xenial:~$ cat docker
    [all:vars]
    ansible_connection=ssh
    ansible_user=MY_USERNAME
    ansible_password=MY_PASSWORD
    
    [docker]
    192.168.85.253

    The [all:vars] section configures the connection settings for all hosts in the file. The [docker] section contains the lists of hosts, in this case just 192.168.85.253.

    Let’s run: ansible -m ping -i docker all, where -m is the module to run, -i is the inventory file, and all is the section of the inventory file which contains the hosts. Notice this is a very special ping.

    vagrant@ubuntu-xenial:~$ ansible -m ping -i docker all
    [DEPRECATION WARNING]: Distribution Ubuntu 16.04 on host 192.168.15.253 should use /usr/bin/python3, but is using /usr/bin/python for backward compatibility with prior Ansible releases. A future Ansible release
     will default to using the discovered platform python for this host. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. This feature will be removed   
    in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
    192.168.15.253 | SUCCESS => {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "ping": "pong"
    }

    Whoa! That definetly doesn’t look like a ICMP ping. First, this is an old box about to be decomissioned, so it has been very unmantained. Ansible warns us about an old version of Python, and a old version of Ansible which was installed previously on the remote hosts.

    Now, try ansible -m setup -i docker all. Be aware this will throw a ton of data to you. The setup module gathers data about the host.

    What it does and how does it, is documented here.