5 avr. 2014

Fill up your servers automatically with goodies


In my former article "Virtualize your servers", we created a virtualized server in few command lines. But... It's empty as the void in space (or so we think...). Still, you can log in easily with:
vagrant ssh
It is now time to fill it with some goodies: NGINX with all the bells and whistles.

Saltstack to the rescue

There are many provisionner available for Vagrant: Chef, Puppet, DockerSaltstack, ... even simple bash scripts. A provisionner acts as framework for creating scripts that will fill your server wether they are physical or virtual. Note that as the servers may be virtual or physical, we will simply refers them as nodes. Nodes are the processing unit of your private cloud, wether it be a single to thousands machine.

Depending on the provisionner you choose, you may have more power for addressing use case scenarios such as:
  • Managing a common configuration for each node with specialization for some of them.
  • Configuring IP addresses and routes for each node.
  • Managing states for each node: a state is an expected running configuration.
  • Upgrading each node and letting the other knows about it while limiting the impacts on service unavailability.
I've chosen Saltstack as it covers these capabilities and the configuration files, the minions, that you write are simplistic and well organized.

Make Vagrant knows about Saltstack

Vagrant speaks Saltstack out-of-the-box. You only put in your little Vagrantfile where are stored your Saltstack files. Here, I put them in a directory named salt.
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # Name of the node
  config.vm.box = "UbuntuServer"

  # Import a preinstalled Ubuntu Server 12.04 LTS
  config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-i386-vagrant-disk1.box"

  # Add port forwarding to access service deployed in the node
  config.vm.network "forwarded_port", host: 8080, guest: 80

  # Synchronized folders
  config.vm.synced_folder "salt/srv/salt/", "/srv/salt/"
  # Use Saltstack as provisioner
  config.vm.provision :salt do |salt|
    # Set the directory where is stored your minion
    salt.minion_config = "salt/minion"
    # Maintain states
    salt.run_highstate = true
Note the option salt.run_highstate = true. It tells  Vagrant to ensure the node state whenever it is executing it.

Here comes the minions

There are 2 ways of using Saltstack: locally or as a server which acts as a repository of minions. In our simple example, we use the most basic way, the local incarnation: masterless. Therefore, the salt/minion file is kept as its bare minimum:
# We run in masterless mode
master: localhost
# We use the local file directory
file_client: local
We use the default Saltstack directory structure to store our minion that will install NGINX:
├── Vagrantfile
└── salt
    ├── minion
    └── srv
        └── salt
            ├── top.sls
            └── webserver.sls
The top.sls file is your entry file to the installation. Here, there is only one formula. Thus, it is pretty straightforward:
    - webserver
The webserver.sls is called by the top.sls. It contains the formula to install and run NGINX as a service:
    - installed
    - running
    - require:
      - pkg: nginx

Get ready!

Now, it's time to fire up everything. If you have just followed my previous tutorial "Virtualize your servers", you should already have downloaded the node's OS. We will destroy it. Yes. Destroy it. This will not re-download the node's OS. It will simply destroy its current customized image. Then, we will rerun Vagrant with our new and fresh configuration. This will do the following:
  • Re-configure the node.
  • Bootstrapping Saltstack into it.
  • Launch Saltstack so that:
    • It install NGINX using the node's OS package manager, apt-get in this case.
    • Launch NGINX as a service.
vagrant destroy
vagrant up
Now, fire up your browser of choice and use the following URL: http://localhost:8080. This should display the NGINX default page just as if you had install it on a regular Ubuntu server.

Next steps

Vagrant and Saltstack are an incredibly powerful combo. In this example, I've made you destroy and reinstalled the node. It was only to ensure a clean state. While creating your server, you don't need to recreate everything and restart your node. Using the states provided by Saltstack, you just modify your SLS files and reprovision the states as you develop them. Iteration are done in a matter of seconds with the command:
vagrant provision
You can install other services as easily. There are some already prepared formulas that you can directly import or take inspiration from in the Saltstack formulas repository.