Creating The Perfect Software Development Environment: Day 07

Installing Development Tools

Last time we installed our IDEs using Ubuntu Snaps. Today, we'll install IDEs using Ubuntu Make.

Ubuntu Make

Ubuntu Make is a command line tool which allows you to download the latest version of popular developer tools on your installation, installing it alongside all of the required dependencies (which will only ask for root access if you don't have all the required dependencies installed already), enable multi-arch on your system if you are on a 64 bit machine, integrate it with the Unity launcher. Basically, one command to get your system ready to develop with!

As I sat down to write this article, I came to a horrible realization: Ubuntu Make does not support unattended installation! This doesn't make it useful during a Packer run but it could be useful to install tools after the box is built. For that reason, we'll install it into the box.


"provisioners": [
    {
        "type": "shell",
        "environment_vars": ["DEBIAN_FRONTEND=noninteractive"],
        "inline": ["sudo snap install ubuntu-make --classic"]
    }
],
            

Tool Installation via Bash

Another way to use the Shell Provisioner is to tell it to run a Bash script, giving you the full power of the Bash shell. This is useful if you have a list of packages to install and don't want to repeat each line.


"provisioners": [
    {
        "type": "shell",
        "environment_vars": ["DEBIAN_FRONTEND=noninteractive"],
        "inline": ["sudo snap install ubuntu-make --classic"],
        "script": "scripts/install-packages.sh"
    }
],
            

#!/usr/bin/env bash

export DEBIAN_FRONTEND=noninteractive

PACKAGES=(tree ntpdate grsync)
for package in "${PACKAGES[@]}"
do
    sudo apt-get --yes install $package
done
            

Multiple Shell Scripts

The shell provisioner also lets you run a sequence of scripts. We'll use this form to install packages as well as to prepare the disk for compression.


    "provisioners": [
        {
            "type"            : "shell",
            "environment_vars": ["DEBIAN_FRONTEND=noninteractive"],
            "inline"          : ["sudo snap install ubuntu-make --classic"]
        },
        {
            "type"            : "shell",
            "environment_vars": ["DEBIAN_FRONTEND=noninteractive"],
            "scripts"         : ["scripts/install-packages.sh","scripts/prepare-for-compression.sh"]
        }
    ],
            

#!/usr/bin/env bash

# sometimes the background update process runs and captures the lock
until sudo apt-get -y update; do echo "Waiting for apt lock"; sleep 5; done

echo 'Clearing APT cache...'
sudo apt-get clean

echo 'Zeroing device to make space...'
sudo dd if=/dev/zero of=/EMPTY bs=1M
sudo rm -f /EMPTY
sudo sync
            

Conclusion

Today we learned how to provision the box using Bash scripts. We've also learned how to prepare the disk for better compression during post-processing. Many of you can stop right here and create a Vagrant box customized to your needs. If you want to use a more advanced tool, join us next time where we'll do some provisioning using Ansible.

Full Packer File


{
    "description": "Builds a Xubuntu 18.04 desktop box with various software development tools installed",
    "min_packer_version": "1.2.3",

    "variables": {
        "ssh_name"            : "vagrant",
        "ssh_pass"            : "vagrant",
        "virtualbox_appliance": "bionic-beaver.ova",
        "comment"             : "Test of Vagrant Cloud upload.",
        "cloud_user"          : "{{env `VAGRANT_CLOUD_ACCOUNT`}}",
        "cloud_token"         : "{{env `VAGRANT_CLOUD_TOKEN`}}"
    },

    "builders": [{
        "type"        : "virtualbox-ovf",
        "source_path" : "{{user `virtualbox_appliance`}}",
        "ssh_username": "{{user `ssh_name`}}",
        "ssh_password": "{{user `ssh_pass`}}",

        "boot_wait"           : "30s",
        "format"              : "ova",
        "guest_additions_mode": "disable",
        "headless"            : false,
        "keep_registered"     : false,
        "shutdown_command"    : "sudo shutdown --poweroff now",
        "shutdown_timeout"    : "2m",
        "skip_export"         : false,
        "output_directory"    : "output-virtualbox-ovf",
        "vboxmanage": [
		        ["modifyvm", "{{.Name}}", "--vram", "32"],
		        ["modifyvm", "{{.Name}}", "--memory", "2048"],
		        ["modifyvm", "{{.Name}}", "--cpus", "1"]
	      ],
        "vm_name"             : "packer-bionic-xubuntu"
    }],
    "provisioners": [
        {
            "type"            : "shell",
            "environment_vars": ["DEBIAN_FRONTEND=noninteractive"],
            "inline"          : ["sudo snap install ubuntu-make --classic"]
        },
        {
            "type"            : "shell",
            "environment_vars": ["DEBIAN_FRONTEND=noninteractive"],
            "scripts"         : ["scripts/install-packages.sh","scripts/prepare-for-compression.sh"]
        }
    ],
    "post-processors": [
        [
            {
                "compression_level"  : 9,
                "keep_input_artifact": false,
                "output"             : "vagrant/bionic-xubuntu.box",
                "type"               : "vagrant"
            },
            {
                 "access_token"       : "{{user `cloud_token`}}",
                 "box_tag"            : "{{user `cloud_user`}}/bionic-xubuntu",
                 "type"               : "vagrant-cloud",
                 "version"            : "{{isotime \"2006.01.0203\"}}",
                 "version_description": "{{user `comment`}}"
            }
        ]
    ]
}