Why Rex/Boxes?

As a developer you know the problem that the behavior of production servers is often different than that of your development machine. And the debugging of issues in production is stressfull and annoying.

The problems ranges from wrong versions of a interpreter (for example Perl, PHP, Python, Ruby, ...) over missing libraries up to operating system differences. With Rex/Boxes you can build one Box (VM) for every project you work on and keep your environment clean and consistent.

A few months ago I heard someone saying »Fail early, fail hard«. It is always better to fail on test environments than on production machines.

With Rex/Boxes it is possible to test your Software in an environment close to production.

As a Teamlead it is often not a small task to onboard new team members. With Rex/Boxes new team members can start working in just a few minutes. They can just use the same Rexfile as everyone in the team to create their own development environment in minutes. With the same packages, same versions, same configuration, same ... as everyone in the team.

As a SysAdmin you can build quickly test environments close to production to test new settings or software before they get deployed to production.

Living DevOps

With (R)?ex it is possible to bring Development and Operations close together. Build your environment as a team. Use the knowledge of both to create a perfect environment for your application. Write (R)?ex tasks together, so that you can use the same Rexfile for your test environment and your production environment.

Introduction to (R)?ex and Rex/Boxes

(R)?ex is a tool to provision your Servers. It uses SSH to connect to your servers. You can rollout packages, manage configuration files and deploy software.

Rex/Boxes is a module integrated with (R)?ex to build Virtual Machines with Oracle VirtualBox.

(R)?ex uses a file called Rexfile to control everything. The Rexfile is to (R)?ex as a Makefile to Make. You can also use (R)?ex as a library for your own software. But this will be covered in an other documentation.

A typical Rexfile consist of the authentication definition and a few tasks to do things.

# Rexfile
user 'root';
password 'foobar';

group frontends => "fe[01..10]";

task "prepare", group => "frontends", sub {
   install "apache2";
};

You can see, the Rexfile is simply perl code with a few extra functions to ease working with the systems.

Setup your environment

(R)?ex comes with a tool named rexify. You can use this to create new (R)?ex projects.

If you see something in braces {{foo}} it means that you have to fill in your own things there.

bash# rexify {{project-name}} --template box

This will create a new directory {{project-name}} with a skeleton Rexfile to create new Boxes. Later we will open this file to customize our Box.

Now you can change into the new directory {{project-name}} and run rex to download and create a new box for you.

bash# rex init --name={{vm-name}} --url={{url-to-prebuild-vm-image}}

You can use the prebuild Box images from http://box.rexify.org/ as a starting point and customize them throu (R)?ex tasks.

This command will download an image from the given url and register a new Box in VirtualBox. After this it will start the Box and look for provisioning tasks.

Customize your Box

With the Rexfile it is easy to customize your just created Box. Open the Rexfile and go down to the task »init«.

task "init", sub {

   my $param = shift;

   box {
      my ($box) = @_;
      $box->name($param->{name});

If you don't want to use the command line to set the name of the Box you can put it there.

      # where to download the base image
      $box->url($param->url});

Here you can set the URL where to download the base Box image.

      # default is nat
      $box->network(1 => {
         type   => "bridged",
         bridge => "eth0",
      });

If you want to use bridged networking you can set it here. But be aware, with bridged networking your Box will be available to all other systems on the same net.

      # only works with network type = nat
      # if a key ssh is present, rex will use this to log into the vm
      # you need this if you run VirtualBox not on your local host.
      $box->forward_port(ssh => [2222 => 22]);
        
      # define multiple forwards
      # {{rule-name}} => [{{port-on-workstation}} => {{port-on-box}}] 
      $box->forward_port(
         ssh  => [2222 => 22],
         http => [8080 => 80],
      );

If you want to redirect ports from your Workstation to the Box, you can define them here.

      # share a folder from the host system
      $box->share_folder("{{sharename}}" => "{{/path/on/workstation}}");

You can also share folders from your workstation with the Box.

      # define the authentication to the box
      # if you're downloading one from box.rexify.org this is the default.
      $box->auth(
         user     => "root",
         password => "box",
      );

If you also want to provision your Box with (R)?ex you have to define the authentication information for this box here. Possible options are:

      # if you want to provision the machine, 
      # you can define the tasks to do that
      $box->setup(qw/install_server/);
   };

};

If you want to use (R)?ex to provision your machine you can define tasks to run right after the Box creation. (R)?ex will than login to your Box and do the defined things. For example installing packages, doing special configurations or deploying software.

task "install_server", sub {
   install "apache2";
   install "mysql-server";
    
   file "/etc/my.cnf",
      source    => "files/my.cnf",
      owner     => "root",
      group     => "root",
      on_change => sub { service mysql => "restart"; };

   file "/etc/apache2/httpd.conf",
      content   => template("templates/httpd.conf.tpl"),
      owner     => "root",
      group     => "root",
      on_change => sub { service apache2 => "restart"; };
};

This task will install apache2 and mysql on your Box. After installing the services it will upload a configuration file for both and, if the file was changed, it will restart the services.

You can always run the »init« task if you changed things (like port forwarding, folder sharing, ...). If a Box with the defined name already exists it will just update the settings for this Box.

The most settings can only be changed if the Box is stopped. To stop the box you can call the »down« task.

bash# rex down --name={{vm-name}}

Where to store the Rexfile?

The simpelst way is to store the Rexfile within your project source repository. So it is available for every team member.

Where to get help?

If you have questions don't hesitate to join us on irc.freenode.net in the #rex channel.

You can also join our Googlegroup and ask your questions there.

We are happy for every contribution. So if you want to help fixing bugs or writing new functions you can fork the project on Github.

Fork me on GitHub