Setting up a local Dataset API repository for SmartOS

The Dataset API is a repository for dataset metadata and files for SmartDataCenter, the commercial product from Joyent for managing a private cloud based on SmartOS. The implementation of this API isn’t open, that means you can’t use it with FiFo and/or your own SmartOS nodes for example. Since I use FiFO to manage my private cloud I really wanted a local repository for my datasets, especially the Windows based ones since they aren’t available from Joyents reposity nor datasets.at. Forturnatley for me Daniel “MerlinDMC” Marlon has developed a free Dataset API server (called dsapid), based on CouchDB and Node.JS ,which I can use. With some help from him I’ve set up my server at home and I thought I’d share my experiences on how to make it work.

Installing a new VM to host dsapid

A new json file for the dsapid server.

{
  "brand": "joyent",
  "alias": "dsapid",
  "tmpfs": 1024,
  "image_uuid": "cf7e2f40-9276-11e2-af9a-0bad2233fb0b",
  "filesystems": [
    {
      "type": "lofs",
      "source": "/zones/dsapi-server-data",
      "target": "/database"
    }
  ],
  "nics": [
    {
      "nic_tag": "admin",
      "ip": "192.168.1.123",
      "netmask": "255.255.255.0",
      "gateway": "192.168.1.1"
    }
  ]
}

This one is based on SmartMachine base64 1.9.1. I’m using a lofs mount to get direct access to a directory under /zones in the GZ, this directory will hold the CouchDB database. You might also want to use a bigger tmpfs if you plan on using big datasets, the dataset is uploaded to /tmp before it’s imported into CouchDB. I use a tmpfs that’s 8 GB, but that’s not big enough sometimes (as you’ll see if you continue reading).

Installing software in the new dsapid zone

It’s time to install the software needed.

pkgin in couchdb nginx node gcc47 gmake scmgit
mkdir /opt/dsapi-ui
chown -R couchdb:couchdb /database

The software is installed and the proper directories created. The dsapid server will be installed later once the database, web server etc. are configured.

Configuration of the installed software

Add the following to /opt/local/etc/couchdb/local.ini under [couchdb]:

database_dir = /database
view_index_dir = /database

To make sure we get periodic syncing from the dataset source (which can be Joyent repo, datasets.at or some other dataset API server), add the following to crontab:
0 * * * * /opt/dsapi/sbin/dsapi-sync-manifests
0 * * * * /opt/dsapi/sbin/dsapi-sync-files

Time to configure nginx, replace the contents of /opt/local/etc/nginx/nginx.conf with the following:
user   www  www;
worker_processes  1;

events {
  # After increasing this value You probably should increase limit
  # of file descriptors (for example in start_precmd in startup script)
  worker_connections  1024;
}

http {
  include       /opt/local/etc/nginx/mime.types;
  default_type  application/octet-stream;

  sendfile        on;
  #tcp_nopush     on;
  tcp_nodelay     on;

  #keepalive_timeout  0;
  keepalive_timeout  65;

  gzip               on;
  gzip_http_version 1.1;
  gzip_proxied      any;
  gzip_vary          on;
  gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
  gzip_disable "MSIE [1-6]\.(?!.*SV1)";
  gzip_buffers    16 8k;

  client_max_body_size 1024m;

  server {
    listen       80;
    server_name  localhost;
    root         /opt/dsapi-ui;

    location = /ping {
      proxy_pass http://localhost:8080;
    }

    location = /stats {
      proxy_pass http://localhost:8080;
    }

    location = /datasets {
      proxy_pass http://localhost:8080;
      proxy_read_timeout 500;
      proxy_connect_timeout 500;
    }

    location ~* ^/datasets/[a-f0-9-]+$ {
      proxy_pass http://localhost:8080;
      proxy_read_timeout 500;
      proxy_connect_timeout 500;
    }

    location ~* ^/datasets/[a-f0-9-]+/.+ {
      proxy_pass http://localhost:5984;
      proxy_read_timeout 500;
      proxy_connect_timeout 500;
    }
  }
}

Increase client_max_body_size to the same as your tmpfs size if you increased that earlier. I’ve also added high timeouts to make sure there’s enough time to upload big datasets.
Now it’s time to start the services we’ve configured.
svcadm enable epmd:default
svcadm enable couchdb:default

Installing dsapid

It’s time to install the dsapid server.

git clone git://github.com/MerlinDMC/smartos-public-dsapi.git /opt/dsapi
cd /opt/dsapi
npm install
svccfg import /opt/dsapid/smf/dsapid.xml
svcadm enable dsapid:default
svcadm enable nginx:default

Adding remote dataset API servers for syncing

If you want to sync an external dataset server, do the following (use -f for manifests AND dataset image files).

/opt/dsapi/bin/add-sync-source joyent https://datasets.joyent.com/datasets (fetch only manifests files get served from the joyent server)
/opt/dsapi/bin/add-sync-source joyent https://datasets.joyent.com/datasets -f (fetch manifests and files)

Installing the web GUI

There’s a web GUI for the dataset server, although it’s made for datasets.at it will work internally (with some stuff still referring to datasets.at).

curl -O https://dl.dropbox.com/u/2265989/SmartOS/dsapi-ui.tar.bz2
tar -xjf dsapi-ui.tar.bz2 -C /opt/dsapi-ui

The web GUI should be available at http://[hostname]

Uploading your own datasets

To start with you need a username and an associated password to be able to upload.

/opt/dsapi/bin/grant-upload [username] [password]

If you haven’t created a dataset before, read my blog post about how to do it. Once you have your manifest file and dataset image file, it’s time to upload it. This is done with curl, for example.
curl -X PUT -u [username]:[password] -F manifest=@[manifest name].dsmanifest -F [image name]=@[image name] http://[dsapi server]/datasets/[dataset UUID]

The “image name” will be something like winserver.zvol.gz or testzone.zfs.bz2. The dataset UUID is the same UUID that you gave the dataset during creation.

If you for some reason don’t get a dataset fully uploaded you’ll have to delete it through Futon, CouchDB’s web management GUI, manually. If you don’t want to change the configuration on the server, which says that CouchDB is only listening on localhost, you can set up a SSH tunnel to access Futon. You’ll probably have to reconfigure sshd to allow root login with a password or add your public key for SSH login.

ssh -f -L 127.0.0.1:5984:127.0.0.1:5984 root@[dsapi server] -N

Now you can access Futon on http://localhost:5984/_utils/ and delete the document created for the dataset (named its UUID).

This is everthing you need to use the dsapi server. To use it with imgadm:

echo "http://[dsapi server]/datasets" > /var/db/imgadm/sources.list
imgadm update

Installing very big datasets

Datasets that are very big will need a very big tmpfs. If you’re dataset is 4 GB you will need over 8 GB of tmps. If you don’t have enough memory you can bypass nginx, which is usually used, and communicate directly with dsapid. By doing this you will only need ~4 GB tmpfs if you are importing a 4 GB dataset.

Start by disabling nginx.

svcadm disable nginx

The next step is to get dsapid to listen on 0.0.0.0 instead of 127.0.0.1. You can disable dsapid in the way you did with nginx and set an env variable (DSAPI_HOST to 127.0.0.1) and start dsapid manually. This won’t persist, if you want this to be persistent:

  • Disable dsapid
  • Remove dsapid using svccfg delete dsapid
  • Edit /opt/dsapi/smf/dsapid.xml and change the DSAPI_HOST variable in the xml file
  • Import the xml file again using svccfg import /opt/dsapi/smf/dsapid.xml

Now you can install the big dataset, use port 8080 with curl. When done you can change back to using nginx. You could (probably) compile nginx with an upload module, but since the nginx available in pkgin doesn’t have this I haven’t tried it.

Using the local dsapid with FiFO

The dsapid is now working with imgadm in native SmartOS, but as I mentioned in the beginning of the post I use FiFo to manage my VMs. To get this working you need some extra tweaks. To start with you need to add the following to your dsapid servers nginx.conf.

if ($request_method = 'OPTIONS') {
   add_header 'Access-Control-Allow-Origin' '*';
   add_header 'Access-Control-Allow-Credentials' 'true';
   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
   add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
   add_header 'Access-Control-Max-Age' 1728000;
   add_header 'Content-Type' 'text/plain charset=UTF-8';
   add_header 'Content-Length' 0;
   return 204;
}

if ($request_method = 'POST') {
   add_header 'Access-Control-Allow-Origin' '*';
   add_header 'Access-Control-Allow-Credentials' 'true';
   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
   add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}

if ($request_method = 'GET') {
   add_header 'Access-Control-Allow-Origin' '*';
   add_header 'Access-Control-Allow-Credentials' 'true';
   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
   add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}

Add this to the last three “location” statements containing references to /datasets and restart nginx. Now it’s time to make the last change, tell FiFo to use the local dsapi server. Edit /opt/local/jingles/app/scripts/config.js and change the following line:
datasets: 'datasets.at',

Change from datasets.at to whatever your server is called.

Done. Enjoy using your local Dataset API Server!

Clustered FiFo nodes

I want to start out by mentioning that this is HIGHLY experimental, try it at your own risk. FiFo has a neat feature for clustering so that your FiFo system keeps functioning even if you lose a node. The data in the cluster is distributed over all the nodes, this means you need two functioning nodes at all times, a good idea is to run this with at least four nodes so that you can lose two nodes.

Installing a new node

Start by installing a new node, follow http://project-fifo.net/display/PF/Installation+Guide and finish step four (4) in the dev part of the guide. Do this for all nodes you want to add (and make sure the first node uses the same version).

Joining the cluster

Run the following commands to join Sniffle, Snarl and Howl to the cluster:

/opt/local/sniffle/bin/sniffle-admin join sniffle@[IP of first node]
/opt/local/snarl/bin/snarl-admin join snarl@[IP of first node]
/opt/local/howl/bin/howl-admin join howl@[IP of first node]

Hopefully it’ll look like this:

[root@fifo2 ~]# /opt/local/sniffle/bin/sniffle-admin member_status
================================= Membership ==================================
Status     Ring    Pending    Node
-------------------------------------------------------------------------------
valid      50.0%      --      'sniffle@172.16.0.11'
valid      50.0%      --      'sniffle@172.16.0.16'
-------------------------------------------------------------------------------
Valid:2 / Leaving:0 / Exiting:0 / Joining:0 / Down:0

Repeat this for the rest of the nodes.

Extended CPU monitoring for SmartOS with Nagios

A while ago I wrote a Nagios plugin to monitor CPU load in SmartOS. I’ve updated that plugin to support individual monitoring of each core, that means you can have a more precise monitoring. In addition I’ve created a template for PNP4Nagios which you can use with the new script. It handles numerous cores automatically depending on how many are fed into Nagios by the monitoring script.

Creating SmartOS datasets

Datasets are images that you can base your VMs on, for instance a dataset can contain a basic Ubuntu 12.04 LTS Server installation. Joyent provides a wide range of datasets that you can access via imgadm, if that’s not enough you can add the community dataset provider datasets.at for an even wider range. This is all good, but sometimes you need to customize or run OSes that aren’t free software. In my example I’ll create a dataset for Windows Server 2012.

Preparations

Install a Windows Server 2012 VM, make sure you install the virtio drivers for the storage and NIC. Then sysprep the machine.

Creating the dataset

The actual creation of the dataset begins with a snapshot. The snapshot is then sent to a file which is gzipped.

zfs snapshot zones/[VM UUID]-disk0@dataset
zfs send zones/[VM UUID]-disk0@dataset > win2012.zvol
gzip win2012.zvol

The next step is to create a dataset manifest file. It looks like this.
{
  "name": "win2012standard",
  "version": "1.0",
  "type": "zvol",
  "cpu_type": "host",
  "description": "Windows Server 2012 Standard VM image 1.0",
  "created_at": "2013-03-07T11:40:00.000Z",
  "updated_at": "2013-03-07T11:40:00.000Z",
  "published_at": "2013-03-07T11:40:00.000Z",
  "os": "windows",
  "image_size": "40960",
  "files": [
    {
      "path": "win2012.zvol.gz",
      "sha1": "792ea932dfa38bb4570a3c760ba1a25277c94ef4",
      "size": 4095909399
    }
  ],
  "requirements": {
    "networks": [
      {
        "name": "net0",
        "description": "public"
      }
    ]
  },
  "disk_driver": "virtio",
  "nic_driver": "virtio",
  "uuid": "3cf8fa80-8711-11e2-9e96-0800200c9a66",
  "creator_uuid": "d989b0a0-8663-11e2-9e96-0800200c9a66",
  "vendor_uuid": "d989b0a0-8663-11e2-9e96-0800200c9a66",
  "owner_uuid": "d989b0a0-8663-11e2-9e96-0800200c9a66",
  "creator_name": "Marcus Wilhelmsson",
  "platform_type": "smartos",
  "urn": "smartos:nickebo:win2012standard:1.0"
}

Please adjust the file, create new UUIDs, etc. When this is done, the dataset is ready to be installed.
imgadm install -m [manifest file] -f [snapshop zvol].zvol.gz

That’s it, you can now use your new dataset as a template when creating new VMs.

 

Adding an environment variable to a service in SMF

Since I’m using NRPE to monitor my SmartOS node I want to be able to use Nagios plugins. The plugins, when installed with pkgin or manually, are added to /opt/local/libexec/nagios or /opt/custom/libexec/nagios and the libraries which the plugins are dependent on are installed to /opt/local/lib or /opt/custom/lib, depending on your preferences. These directories aren’t in the default LD_LIBRARY_PATH in SmartOS, that means NRPE won’t find them.

If you want NRPE to find the libraries you need the LD_LIBRARY_PATH environment variable set manually. This is done by adding it to the SMF manifest. Hopefully you’ve added your manifest XML-file to /opt/custom/smf, edit it and change from:

<exec_method name='start' type='method' exec='/opt/custom/sbin/nrpe -c /opt/custom/etc/nrpe.cfg -d' timeout_seconds='0'/>

to
<exec_method name='start' type='method' exec='/opt/custom/sbin/nrpe -c /opt/custom/etc/nrpe.cfg -d' timeout_seconds='0'>
 <method_context>
  <method_environment>
   <envvar name='LD_LIBRARY_PATH' value='/lib:/usr/lib:/usr/local/lib:/opt/local/lib'/>
  </method_environment>
 </method_context>
</exec_method>

This will set the variable each SMF starts the service and NRPE will find the libraries.

Installing NRPE in the SmartOS global zone

Are you using Nagios, op5 or some other Nagios based monitoring solution? Then you’ll probably want NRPE installed in the global zone of your SmartOS nodes to monitor them. This is how to do it.

Installing NRPE

Since the GZ doesn’t come with pkgin to install packages by default you have two choices. Install pkgin as described in http://wiki.smartos.org/display/DOC/Installing+pkgin  or you’ll have to install NRPE manually (or with a management tool like Chef, CFengine etc.). I had problems using pkgin in the GZ, for some reason it didn’t install all files in the NRPE packages.

I’m showing you how to do it manually. Start by downloading NRPE from the latest pkgsrc available at smartos.org, for example http://pkgsrc.smartos.org/packages/SmartOS/2012Q4-multiarch/All/nagios-nrpe-2.12nb3.tgz. Unpack the file and copy the contents to /opt/custom. /opt/custom is one of the few places in your SmartOS installation where you can have stuff that persists through reboots. Remove the files starting with +, those contain package information needed by pkgin. NRPE should hopefully be installed under /opt/custom/sbin/nrpe.

Configuration of NRPE

Under /opt/custom/share/examples/nagios/nrpe.cfg you can find an example configuration for NRPE. I copied this file to /opt/custom/etc and modified it for my needs. As the GZ doesn’t have user called “nagios” I’m running it as “nobody”. Also make sure you point it at your scripts nrpe.cfg, mine are installed under /opt/custom/libexec/nagios. The scripts included in the nagios plugins package from smartos.org won’t work under the GZ, just to warn you. Some libraries are missing.

Configure SMF

NRPE should in most cases be started when the SmartOS node starts. To accomplish this a manifest has to be added to SMF, the Service Management Facility. SMF manifests are written in XML, create a manifest XML-file that looks like this.

Now, import it with svccfg import manifest.xml and enable it with svcadm enable nrpe. Now NRPE should be up and running. Finally copy your manifest XML file to /etc/custom/smf. This will add the manifest each time the system boots.

Monitoring CPU load in SmartOS global zone via Nagios

I’ve written a script for monitoring the CPU load in the SmartOS global zone using Nagios. The plugin just checks the momentary CPU load, no average over the last minutes or something like that.
You can find it at GitHub.

https://gist.github.com/linuxprofessor/4491960

https://github.com/linuxprofessor/nagios_scripts/blob/master/check_cpuload.sh

Plex Media Server in a KVM VM under SmartOS

My media center of choice is Plex. Plex is built around a number of clients, available for OS X, iOS, Windows, etc., which all can play your media. In addition to this you use a backend service called Plex Media Server (PMS). PMS runs on Windows, Mac and a number of Linux flavors, including some of the most common NASes.

I’ve been using PMS on my Mac Mini located under my TV, it’s also used to play media,  kind of an all-in-one-solution. But there was one thing bugging me, when I (or one of my friends using sharing through myPlex) was doing a transcoding the CPU load on the Mac Mini would go up. Way up. Mac Minis don’t have the most silent cooling, my living room turned into a room of hurt. I couldn’t stand the fan noise! The solution is to move PMS to another machine and my only option used to be my Synology NAS. But the NAS has a big disadvantage, its CPU is too slow to support transcoding sessions. OK, the NAS isn’t an option then, I needed something else. Then it struck me, I HAVE something else. I have my shiny SmartOS box standing in my server closet. To be honest, it’s pretty much idle except for running my blog and my mail server. This doesn’t consume all of its CPU, not even close.

So then it was decided, Plex Media Server + SmartOS = Golden. PMS isn’t available for SmartOS (or any other Illumos/Solaris/whatever for that matter). My only option was KVM + Linux. Said and done, I created a new KVM VM and installed Ubuntu Server plus PMS, no problem there. In fact, there never was a problem. Everything is working just as it should.

Performance

So it works, but how much CPU does it consume? I played a movie on my iPhone using the Plex client. This means transcoding the movie.

Movie playing on iPhone

Movie playing on iPhone

While doing this I had a look at the CPU usage of the Ubuntu machine using prstat -z [ID]. Here’s the output:

CPU usage while transcoding

CPU usage while transcoding

The CPU usage for transcoding a movie in HD is about 25% (on one core).

As far as I’m concerned there’s no disadvantage in virtualising your Plex Media Server, as long as you have enough CPU time for transcoding sessions.

Project FiFo, a promising web interface for SmartOS

SmartOS is, as you might know, a great piece of software. If you’re running machines in the Joyent Cloud (which uses SmartOS) they’ve built a nice web interface for you to handle your VMs. Wouldn’t a software like this be nice to have in your own datacenter/cloud? You might not be prepared to pay for Joyents solution, in that case you should have a look at Project FiFo.

Project FiFo is a web interface for your own SmartOS based cloud. The current verison is 0.3, you can find it at http://project-fifo.net/display/PF/Project+FiFo+Home.

I’ve installed project FiFo and it looks really promising. Below you can see some screenshots from my installation.

I’m eager to try out all the new features in Project FiFo, as you can’t do that much administrations of your VMs yet (although creating, restarting, etc. works).