Automated Setup of Software Development Environment

February 26, 2018

Modern software engineering involves many tools for automating and speeding up the process of building, testing and deploying the software we are developing. One interesting side effect is the potential of those tools when it comes to the set up of your local development environment.

Using tools like Ansible you can e.g. automate the setup of your IDE, the installation of necessary SDKs, the download of code repositories you are working in, and (nearly) everything you need for being able to work. This makes your setup reproducible.

This automated setup can be very handy when combined with virtualization. The main idea is to automatically create and setup a new virtualized software development environment whenever needed.

This blog post shows a sample setup of a new Ubuntu Desktop virtual machine created using Vagrant and provisioned by Ansible. The sample project is available on Github.

Prerequisites

The following explanation is based on a Windows 10 host operating system. The virtual machine used as software development environment is based on Ubuntu 16.04. Please make sure that Vagrant (tested with version 2.0.2) and Virtualbox (5.2.4) are installed on the host system. According to the download page of Virtualbox, the Guest Additions coming with version 5.2.6 of Virtualbox are not working properly on Linux guests with 3D enabled. Therefore Virtualbox 5.2.4 is used when writing this blog post.

In this sample setup it is not necessary to install Ansible, because Vagrant will try to take care of it.

Configure Ansible Roles

We will use Ansible for provisioning our guest system. Most of the logic will be served by existing roles provided by the community via Ansible Galaxy.

The sample setup consists of Intellij Idea as IDE, the Oracle JDK, Git, Maven and Docker. This leads to the sample requirements.yml file shown below. Vagrant will take care of downloading the required files.

- name: intellij-idea
  src: gantsign.intellij

- name: oracle-jdk
  src: gantsign.java

- name: git
  src: geerlingguy.git

- name: maven
  src: gantsign.maven

- name: docker
  src: angstwad.docker_ubuntu

If you are creating your own setup, there might be different entries resp. other role providers. Just have a look at Ansible Galaxy and add the roles fitting your needs.

One custom role is needed for installing the Ubuntu desktop. The relative path to the file should be roles\desktop\tasks\main.yml. The content of this file should look similar than the example shown below. It simply takes the corresponding Debian package and installs it.

- name: Install ubuntu-desktop
  apt:
    pkg: ubuntu-desktop
    state: present
    update_cache: yes

Another custom role is needed for creating a new user. The relative path to the file should be roles\user\tasks\main.yml. The login name of the user will be developer. The password is set to mimacom. Please note that you need to specify the password hash, which can be generated by calling mkpasswd --method=sha-512 on most Linux systems. For further details please have a look at the documentation.

- name: Add personal user
  user:
    name: developer
    password: $6$7t98MX2fDZ$9GC3GX6RaymC/jEyK5LP.F.hQLirmQFN3Z82T6P4AwEGKueBNlJnB3wMxWaiXpiS95UQlz6sBBoe4W9ZwKK3A1
    group: sudo

Create the Ansible Playbook

The next step is creating the Ansible playbook. It references the previously defined roles provided by the community and the custom ones. An example of the playbook is shown below.

In addition to listing all roles, a few parameters need to be added. For installing the Oracle JDK we need to accept the license agreement by adding a corresponding text as parameter. In case of Intellij Idea we would like to use the ultimate edition, which is not the default one chosen by the role.

The last parameter you could optionally add is used for the Docker role. It's effect is, that our newly created user will be added to the docker group for easier usage of Docker without sudo. Please have a look at the documentation, because this impacts security on your system.

- hosts: sde
  roles:
  - role: desktop
  - role: user
  - role: git
  - role: oracle-jdk
    java_license_declaration: 'I accept the "Oracle Binary Code License Agreement for the Java SE Platform Products and JavaFX" under the terms at http://www.oracle.com/technetwork/java/javase/terms/license/index.html'
  - role: maven
  - role: intellij-idea
    intellij_edition: ultimate
  - role: docker
    docker_group_members:
      - developer

The requirements.yml and the playbook.yml files can now be used to set up a Debian based system as software development environment - either on the host system or on a virtual guest system.

Create the Vagrant Configuration

The next step is defining a new virtual machine with Vagrant. This is done by creating a Vagrantfile in the directory of your Ansible configuration.

The Vagrantfile of the sample project is shown below. We will use the Ubuntu Xenial image (16.04). Beside this general Vagrant setting, there are some more settings in the Virtualbox specific part.

Due to the fact that we will use the desktop environment of the virtual machine, we need to show the GUI. The setting related to uartmode1 significantly speeds up the boot time of the new virtual machine as stated in this discussion. There are some more settings, which you might want to customize (e.g. memory, CPU count etc.).

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"

  config.vm.provider :virtualbox do |vb|
    vb.gui = true
	vb.memory = 8096
	vb.cpus = 2
	vb.customize ["modifyvm", :id, "--uartmode1", "disconnected"]
	vb.customize ["modifyvm", :id, "--vram", "256"]
  end

  config.vm.provision "ansible_local" do |ansible|
    ansible.groups = {
      'sde' => ['default']
    }
	ansible.sudo = true
	ansible.galaxy_role_file = 'provisioning/requirements.yml'
    ansible.playbook = "provisioning/playbook.yml"
  end    
end

The key part of the configuration is the provisioning section. We will use ansible_local, i.e. Ansible is not needed on the host system. Vagrant will try to install Ansible inside the new virtual machine. Ansible playbooks will then be directly executed on the guest system. Further details are available in the Vagrant documentation.

We need to assign the guest machine to the host group sde, which is referenced in the playbook. Additionally we give sudo rights. As most important part, the path to the requirements file and the playbook are configured. The provisioner will take care of downloading all external roles and then executes the specified playbook.

Before creating and starting the virtual machine, you could install a plugin called vagrant-vbguest by executing vagrant plugin install vagrant-vbguest. It takes care of installing the host's version of the Guest Additions on the guest system automatically.

Finally the new virtual machine is created and started by executing vagrant up in the directory containing your Ansbile and Vagrant configuration files. After the virtual machine is created, the provisioner is triggered automatically. This might take some time to finish (approx. 5-15 minutes).

Once this process ended, you need to restart the guest with vagrant reload. You should then see the Ubuntu login screen in a Virtualbox window. You can now log in by choosing the developer user with the password mimacom.

Login screen

Conclusion

This blog post has shown, how you can automatically set up a new software development environment in a virtual machine from scratch by using a combination of Ansbile and Vagrant. From my personal point of view, this leads to the following potential benefits:

The example provided here can be used as a starting point, if you'd like to test it on your own. The sample project is available on Github.

About the author: Andreas Hirsch

Andreas Hirsch is a Software Architect at mimacom.

Comments
Join us