• ALL
  • CATEGORIES

Creating WebCenter Sites environments, part 1: setting up

This is the first tutorial in a series of posts looking at setting up a Continuous Delivery pipeline for development with Oracle WebCenter Sites. In this post we’re starting right at the beginning with a look at creating environments to support WCS development.

We’ll look at creating environments that are as alike as we can make them, up through the stack from development, through test, up to production environments. We’ll also look at automating this process because you know…

In more detail we’ll look first at creating a WebCenter Sites development environment. To do that we’ll need to automate the installation and configuration of WebCenter Sites. In order to install WCS we also need to install and configure some supporting software.

This includes:

  • An operating system (Centos 6.6)
  • An application server (Tomcat 7.0.62)
  • A database (Oracle 11g XE)

To make the process repeatable we’ll be encapsulating all the logic by using a Configuration Management tool called Ansible.

In the second part of this post we’ll use a tool called packer.io to create machine images that make it quick and easy for our developers to get a development environment up and running. Packer gives us two key benefits. The first is that this process of producing a development environment is repeatable and the second is that the process of producing machine images can be extended to a range of output formats, but more on that later.

Now, because this post is quite long, here are some handy jumplinks:

Why do we need identical environments?

Before we get going it’s worth talking a little about why we would want to do any of these things. I mean this set-up takes a little bit of work so let’s start with a business case of sorts.

Reduce the capacity for surprise

How many times as a developer have you deployed code into a test environment only for it to fail because the test environment is configured differently in some way? Perhaps a different database, or a different version of the application server? Perhaps even a different patch version of WebCenter Sites. Even worse, how many times has that happened in production?

We can mitigate the risk of these sorts of problems by trying to make our development and test environments as ‘Production Like’ as possible. This means the same OS and the same versions of supporting applications configured in the same way. We should also be able to deploy our code in the same kind of way as we do in production so we know better how that process is going to behave.

Avoid drift

Managing environments is hard, managing them manually is really hard. Martin Fowler talks about what he calls SnowflakeServers – these are environments that have been hand crafted and require tweaking and updating manually. The problem here is when configuration needs to change, whether this is in production or development.

Firstly, making those changes manually has an associated risk that somebody gets it wrong. Secondly, the more servers you have to update the greater the risk that you forget one, or that the change isn’t applied in exactly the same way. Once this happens the configuration of your environments starts to drift. I see this problem particularly often between environment tiers like Test and Production.

There are a number of good ways to solve the problems described above. We’ll focus on two of them: describing the configuration of our environments using recipes; and using those recipes to create golden masters.

A good way of ensuring you are avoiding snowflakes is to use PhoenixServers. Using version-controlled recipes to define server configurations is an important part of Continuous Delivery.
– Martin Fowler

Configuration Management tools

There are a number of well used Configuration Management tools available now – Puppet and Chef get a lot of mindshare but for this tutorial I wanted to look at another tool called Ansible. The thing I like best about Ansible is its love of the shell.

As much as I like writing Ruby, if there’s something I want automate in an environment, I’ll typically turn to bash first. Ansible feels to me like an extension of shell scripting and because of that the process of building Ansible recipes (or playbooks) feels like it involves less cognitive friction.

Your tastes might be different however and the basic premise of what follows is as easily implemented using Puppet or Chef.

Getting started

Before we build our development environment we’ll need to firstly install some software on our local machine and secondly download some software from Oracle – this is because of Oracle’s license restrictions.

On your local machine:

Disclosure – I installed vagrant using the provided installer for Mac OS X and I installed Packer using HomeBrew.

Download the Oracle software:

Next, somewhere on your local filesystem clone our starter repo from github

git clone https://github.com/Manifesto-Digital/wcs-env-tutorial

and then move into that directory.

It’s worth noting that this repository has a number of branches included that will help you follow along with the tutorial – you don’t have to use these branches but hopefully they give you something to compare to if you’re following along yourself.

Introduction to Vagrant

Inside our starter project are a number of folders and files but let’s start with looking at vagrant first. If you want you can change the branch of your local git repo to this starting point, or you can start by just copying the vagrant file below

git checkout 1-intro-to-vagrant

The following code block shows what your Vagrantfile should look like at this point.

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.

Vagrant.configure(2) do |config|

  config.vm.box = "opscode_centos-6.6"
  config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.6_chef-provisionerless.box" 

  config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "1024"]
  end

  # Application server.
  config.vm.define "wcs-server" do |app|
    app.vm.network "forwarded_port", guest: 80, host: 8080, auto_correct: true
  end    
end

Most of this is fairly vanilla but it’s worth pointing out a couple of things.

The first is that for now we’re using Vagrant Box provided by someone else. Once we get to looking at Packer we’ll replace it but for now we’re using a Centos 6.6 box from the Bento project. Bento is a project from the test engineers at Chef to provide Vagrant test environments and therefore provides a whole range of good starter Vagrant boxes.

The second is that we’re changing the RAM our VM will startup with in preparation for the software that we’ll look to add later.

And thirdly we’re setting up some networking for our box: we’re forwarding port 8080 on our local machine to port 80 on the Vagrant box.

Let’s start by bringing our vagrant box up. From your command line issue the following command:

vagrant up

If this is the first time you’ve issued the command you should see Vagrant start by downloading the referenced opscode box. Once that’s complete you should be able to connect to the box by issuing the following command

vagrant ssh

This will take you into a shell inside your vagrant box as the vagrant user. This user has sudo access so if you want to perform a task as the root user, you can.

Let’s start by doing something temporary to test our networking setup. From within the vagrant box issue the following command

sudo yum -y install httpd && sudo service httpd start

This should install and start an instance of the Apache Web Server which you can validate by opening a web browser and navigating to http://localhost:8080 where you should see the Apache test page.

Finally lets clean up by destroying our vagrant box

vagrant destroy

Introduction to Ansible

So now that we have the basis of our Development environment (an OS basically) we need to start installing software in our Vagrant box. To do that we’ll be using Ansible to write some playbooks. These playbooks include the instructions for installing our software in a kind of recipe format. Again you can either checkout the branch that maps to where we are in the process or you can follow along manually.

git checkout 2-intro-to-ansible

The first thing you’ll notice is that we’ve made some changes to our Vagrantfile which now looks like this:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.

$script = <<SCRIPT
if [ "$(( $(cat /proc/swaps|wc -l) - 1 ))" -eq 1 ]; then
sudo mkdir -p /mnt/swap
cd /mnt/swap/
sudo dd if=/dev/zero of=swapfile bs=1M count=1536 
sudo mkswap swapfile 
sudo swapon swapfile
fi
SCRIPT

Vagrant.configure(2) do |config|

  config.vm.box = "centos-6.6-virtualbox"
  config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.6_chef-provisionerless.box" 

  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end

  # Application server.
  config.vm.define "wcs-server" do |app|
    app.vm.hostname = "wcs.192.168.60.5.xip.io"
    app.vm.network :private_network, ip: "192.168.60.5"
    app.vm.provision "shell", inline: $script
    app.vm.network "forwarded_port", guest: 8080, host: 8080, auto_correct: true
    app.vm.network "forwarded_port", guest: 1521, host: 1521, auto_correct: true      
    app.vm.network "forwarded_port", guest: 9090, host: 9090, auto_correct: true
    app.vm.provision "ansible" do |ansible|
      ansible.playbook = "wcs.yml"
      ansible.inventory_path = "hosts"
      ansible.verbose = "extra"
      ansible.limit = 'all'      
    end
  end  
end

There’s quite a bit of change here so let’s take it one bit at a time.

Temporary horrible swap hack

To start with we have a a little bit of inline provisioning that looks like this. I won’t spend too much time talking about it as we’re going to remove it later. It’s here to help us get Oracle XE installed as the DB installer gets a little upset if we don’t have enough swap space in our VM. Don’t worry though: we’ll fix things up properly when get to using packer in the next post.

$script = <<SCRIPT
if [ "$(( $(cat /proc/swaps|wc -l) - 1 ))" -eq 1 ]; then
sudo mkdir -p /mnt/swap
cd /mnt/swap/
sudo dd if=/dev/zero of=swapfile bs=1M count=1536 
sudo mkswap swapfile 
sudo swapon swapfile
fi
SCRIPT

Next we’ve added some extra network configuration to make things a bit easier for our developers.

Firstly there are some more forwarded ports. These are for making access to the DB a bit easier (1521 and 8080 is now used for the database admin webapp) and we’ve added another new mapping for our application server tomcat (9090).

Secondly we’ve changed the network configuration so that we’re using a local private network and we’ve added a hostname that maps a fqdn to our local IP address. To do this we’re using a service called xip.io that provides DNS mapping to any IP address as long as you use their format.

Finally we’ve added in a provisioning block that kicks off our Ansible playbooks. The provisioning looks like this:

  app.vm.provision "ansible" do |ansible|
      ansible.playbook = "wcs.yml"
      ansible.inventory_path = "hosts"
      ansible.verbose = "extra"
      ansible.limit = 'all'      
  end

Simply it tells vagrant where to find some important ansible files like the main playbook and our inventory.

Our main ansible playbook is called wcs.yml and sits in the main directory. Lets have a quick look at it:

---
# file: wcs.yml
- hosts: webservers
  sudo: true
  roles:
    - common
    - {role: oracle, tags: ["oracle"]}
    - {role: tomcat, tags: ["tomcat"]}
    - {role: web-center-sites, tags: ["wcs"]}      

In essence we’re saying we want to run the roles oracle, tomcat and web-center-sites in that order.

Installing Oracle XE

Now we’re going to install Oracle XE. But first we need to place the oracle rpm archive we downloaded right at the beginning and place it within the roles/oracle/files directory.

The filesystem layout for our Ansible role should like this:

- oracle
   - files
       + oracle-xe-11.2.0-1.0.x86_64.rpm.zip
   - tasks
       + main.yml
   - templates
       + xe.rsp

Files

This is where we put the Zip archive that contains the Linux RPM for installing Oracle.

Tasks

This is where we put the files describing the tasks to be performed as part of running this playbook. It’s the meat, if you like. If you have a look at this main.yml task file you can see it’s fairly simple. Breaking it down we do the following:

  • Install some required packages using yum
  • Unzip the archive containing the RPM
  • Install the RPM
  • Create the response file used as part of the post install configuration
  • Run the post install configuration
  • Add the oracle env variables to the vagrant users bash profile

Templates

This where we put our template files. These are files used in the installation that will have host-specific values. For example in our case we’re creating a response file (xe.rsp) for the Oracle installer that provides values for the database ports and credentials.

Installing Tomcat

The role we’ve created for installing tomcat is very similar in structure and is based on this example provided by Ansible

- tomcat
   - files
       + tomcat-initscript.sh
   - tasks
       + main.yml
   - templates
       + server.xml
       + tomcat-users.xml

Files

This includes our service script for tomcat.

Handlers

This directory includes a file called main.yml that describes operations that are run upon notification. A good example, and the one used here, is restarting a service when a configuration file changes.

Tasks

Again this main.yml file describes the tasks required to install and configure tomcat. They can be broadly described as:

  • Install Java
  • Download the Tomcat binary
  • Create install directories and SymLinks
  • Create Tomcat users/groups
  • Make sure all directories are owned by the new tomcat user
  • Create the Tomcat server.xml configuration file
  • Create the Tomcat tomcat-users.xml configuration file
  • Put the Tomcat initscript in place

Templates

Our template files here are the server.xml and the tomcat-user.xml file

Automating a WebCenter Sites installation

With our database and application server in place the next step is to perform that actual installation of WebCenter Sites.

Let’s start by looking at our Ansible role – this should be starting to look familiar to you by now.

- web-center-sites
   - files
       + ofm_sites_generic_11.1.1.8.0_disk1_1of1.zip
       + ojdbc6.jar
   - tasks
       + main.yml
   - templates
       + catalina.properties
       + catalina.sh
       + create_wcs_user.sql
       + customBeans.xml
       + generic_omii.ini
       + install.ini
       + installer.sh
       + server.xml

Files

The in this directory are some of the ones we downloaded previously namely the WCS installer archive and the Oracle JDBC driver.

Tasks

Our main.yml tasks file includes the following instructions:

  • Install Java
  • Install NetCat (used for running the installer in the background and to be able to pipe input)
  • Create the database setup script
  • Create the database
  • Unzip the WCS installation archive
  • Create directory for the installer to run from
  • Unzip the Sites part of the install suite
  • Create shared directory
  • Create the WCS home directory
  • Move the JDBC driver into the tomcat lib
  • Add WCS parameters to the tomcat startup script (catalina.sh)
  • Create the ini file that drives the silent installer
  • Create the installer configuration file
  • Update the tomcat server.xml file with details of the WCS datasource
  • Update the catalina.properties file to add the WCSHOME/bin directory to the classpath
  • Create the installer.sh silent install wrapper script
  • Execute the installer.sh script
  • Update the customBeans.xml configuration file that controls the urls that WCS trusts access from
  • Restart tomcat_

Which is a whole lot of stuff going on. Perhaps the most interesting is the installer.sh script (the rest is fairly standard installing-WCS-fare) so let’s continue by having a look at what that script is doing…


!/bin/bash
echo "<<< deploying sites"
cd {{wcs_installer_directory}}/Sites
rm out.log
touch out.log
nc -l 12345 | sh csInstall.sh -silent | tee out.log &
while ! tail -n 1 out.log | grep "press ENTER."
do sleep 1 ; echo ...deploying...
done
echo ">>> deploying sites"

echo "<<< starting tomcat"
/usr/share/tomcat/bin/startup.sh
while ! wget -q -O- http://{{wcs_install_webserver_address}}:{{wcs_install_webserver_port}}/cs/HelloCS | grep reason=Success
do echo "...starting..." ; sleep 1
done
echo ">>> started tomcat"

echo "<<< installing sites"
cd {{wcs_installer_directory}}/Sites
echo | nc localhost 12345
while ! tail -n 1 out.log | grep "Installation Finished Successfully"
do sleep 1 ; echo ...installing...
done
echo ">>> installed sites"

 

Of interest here is the use of NetCat to provide a way of running the installer that allows us to send an ‘Enter’ command to the installer process, once we’ve checked that the web application has deployed correctly. This is a neat little trick that I picked up from here – https://gist.github.com/sciabarra/030bcfc307ff82d57a86

Next time: Packer

So now we have our recipes for automating installation and configuration but we still have a few problems to solve.
The first is that all of this takes a little while to complete.

If we want our developers to be able to recreate their development environments as easily as possible, we also need them to be able to do so as quickly as possible and at the moment that’s not really the case. We also have a little hack in our vagrant file that I promised we would remove. We can solve both of these problems by using a tool called packer, which I’ll introduce in part 2 of this post.

Leave a reply

You can use these tags:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  1. Keith Jones says:

    Loving the use of nc get around that annoying midpoint configuration interactivity requirement. This is the one bit I’d failed to automate thus far – I’m off to update our installation scripts at the earliest opportunity!

  2. Pat Shone says:

    Thanks Keith, it’s useful that, isn’t it – let me know how you get on.

  3. Keith Jones says:

    It worked like a charm, thanks Pat!

Sign up for the Manifesto newsletter and exclusive event invites