Sunday, May 31, 2015

Building an Oracle Linux Amazon Web Services AMI with Packer

No need to explain why Amazon Web Services is a nice platform to run Oracle. The largest IaaS Cloud Provider is one of the few Oracle Authorized Cloud Environments. You can Bring Your Own "Oracle" Licenses (BYOL) on AWS EC2 or RDS. You can pay for what you've provisioned because it is considered as a hard partitioned Platform.

Obviously, there are some drawbacks including the one pointed by Marc Fielding on Pythian's Blog or the fact you cannot run RAC. But it is, for sure, a nice playground to run Oracle technologies, your applications on Oracle or any Oracle applications including JD Edwards, Peoplesoft, Oracle E-Business Suite and many more... In addition, Amazon RDS for Oracle offers an attractive pay-per-use and "per-hour" model for Oracle Database SE1.

On the other hand, Oracle Linux is probably the best operating system to run Oracle, on AWS EC2 like on any x86_64 Platforms: it requires one-only rpm to be ready for most Oracle software; it is free and you don't need to support all your instances the same way as described in the Service Levels section of "Oracle Linux and Oracle VM Support Policies". Last and not least, it is 100% compatible with Redhat Enterprise Linux and you can even get AMIs from Oracle on the AWS Marketplace.

This blog presents and easy and fast way to create an Oracle Linux AMI from the Open Virtual Format (OVF) with AWS VM Import/Export... It relies on Virtualbox, Packer.io and Kickstart.

Cloud-init and Redhat Compatible Kernel

Before you rush to create your AMI, there are 2 things to pay attention to : the first one is that in order for Oracle Linux to install the public key provided when you start instance from EC2, it requires the cloud-init package to be installed and configured. The good news is that the EPEL Repository provides the magic package as well as the ones it depends on. If you don't want to register the EPEL repository directly to your yum configuration, download and install all the required files. Below is a table that references the required links for Oracle Linux 6:
PackageDownload
cloud-init (epel6)RPM Url
python-six (epel6)RPM Url
python-requests (epel6)RPM Url
python-prettytable (epel6)RPM Url
python-jsonpointer (epel6)RPM Url
python-chardet (epel6)RPM Url
python-ordereddict (epel6)RPM Url
python-urllib3 (epel6)RPM Url
python-backports-ssl_match_hostname (epel6)RPM Url
python-backports (epel6)RPM Url
python-argparse (epel6)RPM Url
python-jsonpatch (epel6)RPM Url
python-boto (epel6)RPM Url
python-rsa (epel6)RPM Url

The second thing to pay attention to, is the fact that, among other stuffs, AWS VM Import/Export runs a test instance before it creates the AMI and, as part of it, checks the kernel version. In order to pass the VM Import/Export test, you should configure grub to start the Redhat Compatible Kernel (RHCK). The AMI created, you will be able to modify it to switch to Oracle Unbreakable Enterprise Kernel (UEK).

Kickstart, Packer.io and VirtualBox

If this is a one time only AMI creation, start Virtualbox, proceed with an Oracle Linux installation, export the VM as an Open Virtualization Format set of files and proceed with the AWS VM Import/Export section of this blog. Nevertheless, if you start to walk that way, it very likely you will soon want to automate the Image creation... Kickstart, Packer and Virtualbox are the easiest and most efficient way to automate that task I've found so far. You can proceed as described below.

Use a Custom Oracle Linux ISO

The first step to automate your Oracle Linux installation is to use a "Customized Redhat/Oracle Linux ISOs". You can find an example of the kickstart file I use below:
  • It configures the network with DHCP as it is how AWS works
  • It creates a user named ec2-user and adds it to the sudoers file. This user is both used to access the instance on AWS and by Packer to proceed with some customizations.  
install
cdrom
lang en_US.UTF-8
keyboard fr
network --onboot=yes --device=eth0 --bootproto=dhcp --noipv6
rootpw manager
firewall --service=ssh
authconfig --enableshadow --passalgo=sha512
selinux --disabled
timezone Europe/Paris --isUtc
bootloader --location=mbr --append="rhgb quiet"
text
zerombr
clearpart --all --initlabel
autopart
reboot --eject
user --name=ec2-user --homedir=/home/ec2-user --password=ec2-user --shell=/bin/bash --uid=1501
 
%packages
@base
oracle-rdbms-server-12cR1-preinstall
zip
unzip
%end

%post
echo "ec2-user ALL=(ALL)  NOPASSWD:ALL" >> /etc/sudoers
%end
Important Note:
If you plan to deploy your AMI on AWS, make sure passwords are strengthen and cannot be used to connect via SSH on AWS. Cloud-init does a part of it for you but it doesn't change the root password.

Packer and Virtualbox

If not already done, install Packer.io, Virtualbox and create your custom ISO file. Once done, you should be able to automate the image creation with the ISO and 2 additional files. The ol66.json file below contains a Packer builder configuration and the following parameters:
  • type should be virtualbox-iso to build the OVF with virtualbox
  • iso_url, iso_checksum and iso_checksum_type point to the ISO you've created before
  • ssh_username and ssh_password define how packer connects to the VM to run scripts and perform some operations like the shutdown_command
  • ssh_wait_timeout defines the time to be waited for SSH before the installation fails
  • output_directory and vm_name define the output directory and name
  • guest_additions_mode set to disable prevents VirtualBox Guest Additions installation
  • disk_size specify the size of the system disk
  • provisioners defines scripts or other tasks to be done once the configuration is done
cat ol66.json 
{
  "builders": [
    {
      "type": "virtualbox-iso",
      "guest_os_type": "Oracle_64",
      "iso_url": "file:///home/resetlogs/distribs/linux/OL66-resetlogs.iso",
      "iso_checksum": "e3412215bcee9b825ecfc9376329aa5b",
      "iso_checksum_type": "md5",
      "ssh_username": "ec2-user",
      "ssh_password": "ec2-user",
      "ssh_wait_timeout": "900s",
      "shutdown_command": "sudo -n shutdown -P now",
      "vm_name": "ol66",
      "output_directory": "ol66",
      "guest_additions_mode": "disable",
      "disk_size": "8000"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "script": "scripts/ol66.sh"
    }
  ]  
}
The ol66.sh post-configuration script does the following:
  • it cleans up the network files
  • it changes the grub.conf file to use the Redhat Compatible Kernel
  • it installs and configures the cloud-init rpm
cat scripts/ol66.sh
#!/bin/bash
#
# Update RPMs with the latest release
#
sudo -n yum -y update
#
# Clean the configuration and switch to RHCK before you upload the
# OVF file to AWS...
#
sudo -n sed -i '/SUBSYSTEM/d' /etc/udev/rules.d/70-persistent-net.rules
sudo -n sed -i '/#\ PCI\ device/d' /etc/udev/rules.d/70-persistent-net.rules
sudo -n sed -i '/HWADDR/d' /etc/sysconfig/network-scripts/ifcfg-eth0
sudo -n sed -i '/UUID/d' /etc/sysconfig/network-scripts/ifcfg-eth0
sudo -n head -n 15 /boot/grub/grub.conf
echo "........."
sudo -n sed -i 's/^default.*$/default=0/g' /boot/grub/menu.lst
sudo -n sed -i 's/^default.*$/default=0/g' /boot/grub/grub.conf
echo "........."
sudo -n head -n 15 /boot/grub/grub.conf
#
# Download and install Cloud-Init and required files
#     Note:
#     Future cloud-init should require python-oauthlib-0.6.0-4.el6.noarch.rpm,
#     python-crypto2.6-2.6.1-2.el6.x86_64.rpm and pyserial-2.6-5.el6.noarch.rpm
#      
EPEL6_URL=https://dl.fedoraproject.org/pub/epel/6/x86_64
for i in cloud-init-0.7.4-2.el6.noarch.rpm \
         python-six-1.7.3-1.el6.noarch.rpm \
         python-requests-1.1.0-4.el6.noarch.rpm \
         python-prettytable-0.7.2-1.el6.noarch.rpm \
         python-argparse-1.2.1-2.el6.noarch.rpm \
         python-jsonpatch-1.2-2.el6.noarch.rpm \
         python-boto-2.34.0-4.el6.noarch.rpm \
         python-rsa-3.1.1-5.el6.noarch.rpm \
         python-jsonpointer-1.0-3.el6.noarch.rpm \
         python-chardet-2.0.1-1.el6.noarch.rpm \
         python-crypto2.6-2.6.1-2.el6.x86_64.rpm \
         python-ordereddict-1.1-2.el6.noarch.rpm \
         python-urllib3-1.5-7.el6.noarch.rpm \
         python-backports-1.0-3.el6.x86_64.rpm \
         python-backports-ssl_match_hostname-3.4.0.2-4.el6.noarch.rpm; do
wget $EPEL6_URL/$i >/dev/null 2>&1
RESULT=$?
if [ "$RESULT" -eq "0" ]; then
   echo "$i successfully downloaded..."
else
   echo "$i error downloading..."
fi
done

sudo -n yum -y install *.rpm
sudo -n sed -i 's/name: cloud-user/name: ec2-user/g' /etc/cloud/cloud.cfg
rm *.rpm
So, building the AMI is a one-line command:
packer build ol66.json

AWS VM Import/Export

In order to add your AMI with the others on EC2, you need to use the AWS VM Import/Export utility. Make sure you've installed the AWS CLI as described in the documentation. Assuming you've a S3 bucket named oraclelinuxvms:
  • Upload the disk file to your S3 bucket
aws s3 cp ol66-disk1.vmdk s3://oraclelinuxvms/ol66-disk1.vmdk
upload: ./ol66-disk1.vmdk to s3://oraclelinuxvms/ol66-disk1.vmdk
  • Import the AMI from S3 to EC2
aws ec2 import-image --cli-input-json "{  \"Description\": \"Oracle Linux VMDKs\", \"DiskContainers\": [ { \"Description\": \"Main Disk\", \"UserBucket\": { \"S3Bucket\": \"oraclelinuxvms\", \"S3Key\" : \"ol66-disk1.vmdk\" } } ] }"
{
    "Status": "active", 
    "Description": "Oracle Linux VMDKs", 
    "Progress": "2", 
    "SnapshotDetails": [
        {
            "UserBucket": {
                "S3Bucket": "easyvms", 
                "S3Key": "ol66-disk1.vmdk"
            }, 
            "DiskImageSize": 0.0
        }
    ], 
    "StatusMessage": "pending", 
    "ImportTaskId": "import-ami-fh2lc48d"
}
  • Monitor the import until it succeed
aws ec2 describe-import-image-tasks --import-task-ids import-ami-fh2lc48d
{
    "ImportImageTasks": [
        {
            "Status": "completed", 
            "LicenseType": "BYOL", 
            "Description": "Oracle Linux VMDKs", 
            "ImageId": "ami-0b07757c", 
            "Platform": "Linux", 
            "Architecture": "x86_64", 
            "SnapshotDetails": [
                {
                    "DeviceName": "/dev/sda1", 
                    "Description": "Main Disk", 
                    "Format": "VMDK", 
                    "DiskImageSize": 1187275776.0, 
                    "SnapshotId": "snap-fa88530e", 
                    "UserBucket": {
                        "S3Bucket": "easyvms", 
                        "S3Key": "ol66-disk1.vmdk"
                    }
                }
            ], 
            "ImportTaskId": "import-ami-fh2lc48d"
        }
    ]
}
The AMI name is the import identifier. You can query your AMIs list the new one:
aws ec2 describe-images --filters Name=name,Values=import-ami-fh2lc48d
Unfortunately it is running RHCK. To switch to UEK, create an EC2 instance, change the grub.conf configuration file and recreate an Image like below:
Obviously this step can also easily be automated with the AWS CLI or with Packer and its amazon-ebs builder.

Conclusion and More... 

Once you've built an AMI, you can create new EC2 instances in a matter of minutes and access them with your private key. Check for yourself your pre-backed Oracle Linux Instance running on Amazon Web Services :
uname -a
Linux ip-172-31-35-51 3.8.13-68.2.2.el6uek.x86_64 #2 SMP Tue May 12 15:10:51 PDT 2015 x86_64 x86_64 x86_64 GNU/Linux

Obviously this is just a start! Being able to build customized AMIs reduces the time needed to configure your instances when you start them and can speed up, by an order of magnitude, the time needed to deploy new environments. Not to say, it's a good way to reduce the number of errors compared to some configuration management strategies. This can be key for scenarios like running a Disaster Recover Plan with Oracle on Amazon Web Services or building some test on-demand environments. Combined with Oracle silent installation, it is the basis for faster and safer Oracle deployments...

2 comments:

  1. Hi Greg ! AWS implemented OVM support on Amazon EC2 with hard partitioning so Oracle’s standard partitioned processor licensing models apply. Since few months Oracle Cloud IaaS is available (compute, storage and Network). Except the price which would cost a little bit more for deploying instances into Oracle Cloud, what would be the reason of the users now to stay on AWS and deploy their instances?

    ReplyDelete
    Replies
    1. Hi! I agree with SE. However, when it comes to Enterprise Edition Licenses, I'm not sure Oracle actually costs more compared to Oracle VM; even though AWS stopped OVM way back:
      - The number of virtual core for m4.4xlarge is 8 (see https://aws.amazon.com/ec2/virtualcores/) for a 16 vCPU instance, i.e. 16 threads of a 2.4 GHz Intel Xeon® E5-2676 v3. At least.
      - From Oracle Licensing Oracle Software in the Cloud Computing Environment (http://www.oracle.com/us/corporate/pricing/cloud-licensing-070579.pdf) that would not require more licence than a 16vCPU OracleVM on-premises Instance with Hard or even Trusted Partitioning.
      But I might simply not understand it well.

      Anyway, this article was not advising for one architecture rather than another and definitely not about licensing. I see a lot of people using AWS, including me. That's a good thing they can run Oracle on EC2 or RDS. It is even better if you can run Oracle Linux and one version you can truly customize since the one from Orbitera might have limits sometimes. You might still find people running Oracle EE on HP-UX/IA64 today. Would you say that it is cost effective compare to G9 on Oracle VM?

      Delete