Friday Jun 19, 2009

Typo in OpenSolaris RoR AMI on Amazon EC2

We released a new OpenSolaris Ruby on Rails image on Amazon EC2 last week.  This version is different from the previous one on OpenSolaris because not only does this AMI include the usual goodies, updates etc., this is also a Typo appliance. 

Want some marketing key words?

  • Optimized
  • Secure
  • Pre-configured, preinstalled, and very "appliancy"
  • Extremely monitorable

Since I'm not really a marketing guy, I just can't put words out there without feeling a primordial urge to explain myself.


The stack (Ruby, extensions, gems, web servers) is compiled with the latest compilers, optimal compiler flags based on performance studies, and Nginx is configured to have its temporary file store on a tmpfs mount.


Nothing runs as root, even for an instruction.  If you're wondering how Nginx can listen at port 80 without being started as root, the answer is easy - Solaris privileges:  root is not a user, rather it's a role.  So you can confer privileges (like listening on port 80) which are usually associated with root to other users (like the nginx user).  So this obviates the necessity for applications(like Nginx or Apache) to run as root even for the brief set of instructions needed to bind to a port.  The less instructions you run as root, the less your exposure.

Pre-configured, pre-installed, and very "appliancy".

The image contains a production ready configuration of Typo, which is the popular Rails blog engine(usage details are here[1]).  Its architecture: there are two Nginx workers.  Nginx listens at port 80 and is a fast web server which reduces the possibility of application bottlenecks.  In all likelihood, one cannot fully stress two Nginx workers in an EC2 instance (or even one, in my opinion) In addition, Nginx has a low memory footprint, so the benign effect of having two instances outweighs the overhead). 

The Rails servers are powered by Thin.  There are two instances that Nginx communicates with.  Rails is a CPU-intensive/low concurrency application that benefits from multiple instances.  The Thins are sized in anticipation of a single CPU so it may be wise to increase the number of Thin instances depending on the number of CPUs in the image.

MySQL is the database.  The three tiers are pre-configured.  Nginx communicates with Thin, and Thin communicates with the database.  Typo has its schema populated into the MySQL database, Rails and its dependencies are already installed.  The native gems, like MySQL and Thin have been compiled and configured correctly . . . and it "just works".  To use it start the instance, and log on to http://instance to begin setting up your web log.

SMF services exist for the Nginx, Thin, and MySQL components, and the dependencies between these services are also expressed in the manifests.

The catalog entry has information on where the service manifests are stored, and where the components are installed for one who wants further control.

Extremely monitorable

The AMI has DTrace support.  DTrace provides for a low overhead profiling with fine-grained control over which code is being profiled.  Please refer to Reference 2 below[2].

What's not in the AMI:  one needs a backup mechanism for their weblog entries, this is something that the AMI does not provide at this time. 

And that's it, please check out the AMI, and hope it is useful either in itself, as a starting point for an tiered architecture that can benefit from an SMF integration, and/or as a base Ruby on Rails AMI that can be used for building a private stack.




Wednesday Apr 29, 2009

SMF manifest for Nginx

Here's an SMF manifest for Nginx.  You'll need to tweak it for your location of Nginx.  You can create an nginx user and group to run the web server as(highly recommended), or tweak my script to run as root(please don't do this).

The steps?

  1. Download the SMF from here
  2. groupadd nginx
  3. useradd -d /export/home/nginx -g nginx nginx
  4. change all occurrances of "/usr/nginx/sbin/nginx" to point to where ever your nginx is installed.
  5. You may remove the -c option in the nginx invocation if you do not want to place your nginx config file in that directory(or just want to use the default one).
  6. next, import the SMF script.  svccfg import nginx.smf
  7. run svcs -vx to make sure everything went well. It should have, if you followed all the steps above.( else you'll be pointed to a log file for further debugging )
  8. You are set.
  9. Optional:  add service dependendies on the mysql and thin/mongrel services on your system since nginx probably won't be of much use if you don't have those running.

Monday Apr 27, 2009

Git is in OpenSolaris-dev.

I just noticed that git is available in the OpenSolaris dev repository.  No more compiling from source.  Very cool.  All the volunteer work done to spruce up FOSS support in the OSOL community is paying off. 

You can either get it by running "pkg image-update" on your OpenSolaris instance, or wait for the Ruby on Rails EC2 image which I'm creating right now, to get a preconfigured set of tools, gems, web servers etc.,

Tuesday Feb 10, 2009

Sun Web Stack is now called Sun GlassFish Web Stack.

Nothing else changes - the software that one usually expects to find here, like Ruby, Apache, PHP, MySQL, Memcached and more are still there, and will continue to be. actively developed on and enhanced.

Wednesday Feb 04, 2009

How does one update Ruby in OpenSolaris?

  The package manager UI(or it's command line alternative "pkg" ) in OpenSolaris is the right way to update installed programs.  However, in 2008.11 (and onward) one may find that the package manager does not show that updates are available.  This is because of how the package repositories for OpenSolaris are structured.

 The package manager by default uses the package repository at   This repository is frozen(this is not completely true, since we're allowed to put security patches into the release repository after it's been 'frozen', but new features and other bug fixes are not allowed here) at the time of an OpenSolaris release and is updated only when the next official release occurs.  The 6 + builds that occur before the next freeze(for the next release) are not reflected in this repository. 

 It's a pity - with OpenSolaris, you don't have to worry about build instabilities, crashes etc., given all the good quality assurance that's built into the system - so one might(and probably would) prefer to stay on the latest build without giving up on stability. 

 But have no fear, there is an option for such users - the dev repository.  Please set  as one of your repositories(in the package manger tool).  In fact, I also set it to be my primary repository.  This way you can stay up to date, without waiting for the next official release; the dev repository is updated with every build.  So expect an update every two weeks(approximately).

To update the installed Ruby, click on the "Update all" button - this will download a wad of packages to update your system with.  The update takes a while, but this happens in the background while you continue working.  For other programs you may be able to get away with updating only the concerned package.

Sunday Dec 14, 2008

The curious case of the Ruby T-Square operator.

 The "||=" operator is interesting, both in what it does as much as in how it's widely used in Ruby land.  The operator does not do what you would usually expect.  i.e.,

a ||= expr

is not the same as

a = a || expr

The evaluation happens to be 

a or a = expr

 and the difference is important in at least one use case [0]

As a little DTrace script will verify, this operator is not implemented is a method(or anywhere in Ruby land) and is intrinsic to the VM.   The reason is performance, and the fact that the entire expression does not have to be evaluated to yield a result when you're 'OR'ing:

"Ruby's Boolean operators are built into the language and are not based on methods: classes, for example, cannot define their own && method.  Ruby defines special true and false values but does not have a Boolean type. method. The reason for this is that Boolean operators can be applied to any value and must behave consistently for any kind of operand."

. . .

"Another reason that Ruby's Boolean operators are a core part of the language rather than redefinable methods is that the binary operators are "short-circuiting." If the value of the operation is completely determined by the lefthand operand, then the righthand operand is ignored and is never even evaluated."

 (From The Ruby Programming Language, 1st Edition by David Flanagan and Yukihiro Matsumoto.)

Assuming that variable "a" was not defined prior, then a = a || expr works a little differently than it would if the rvalue was assigned to an lvalue other than a.  That is, if a is not defined, then expr is assigned to a.  If however, a was not present in the lvalue and the rvalue looked the same(say the code looked like b = a || expr ), then the rvalue will fail to evaluate since "a" is not defined.

>> b = a || "Foo"
NameError: undefined local variable or method `a' for main:Object
        from (irb):2:in `binding'
        from C:/Program Files/NetBeans 6.5/ruby2/jruby-1.1.4/lib/ruby/1.8/irb.rb:150:in `eval_input'
        . . .
>> a = a || "Foo"
=> "Foo"

This special operator finds popular usage not in logical "OR"s, but in variable assignment.  It's a Rubyism to instantiate instance variables in methods other than constructors.  

From mongrel_rails (version 1.1.5):

    def config_keys
      @config_keys ||=
        %w(address host port cwd log_file pid_file environment docroot mime_map daemon debug includes config_script num_processors timeout throttle user group prefix)

This deferred assignment is useful in general if your constructor contains many complex instantiations that need not be performed during object construction.  But in this case, it's just a Rubyism.  It's called lazy initialization[1].  There's also an easy patch to make that work transparently if you really like it[2].

There is another occasion to use this Rubyism:  when your method accepts a parameter with a default value that needs to be populated with a method call.  From Rails 1.1:

  def install(method=nil, options = {})
    method ||= rails_env.best_install_method?

It'd clutter the method definition line to have rails_env.best_install_method? all in the same place, and hence is a good way to produce readable code.

This Rubyism is not usable when nil or false are legal values for the variable being thus assigned.

 "For the purposes of all Boolean operators, the values false and nil are considered false. And every other value, including true, 0, NaN, "", [], and {}, is considered true."

 (From The Ruby Programming Language, 1st Edition by David Flanagan and Yukihiro Matsumoto.)

There's another interesting usage, to avoid the "nasty nils", as pointed out in the below comment by Mark Wilden, and here[4]

If you're too young to know what a T-Square is, see [3]






A simple T-Square

Monday Nov 03, 2008

Ruby, concurrency, and --enable-pthread

 Ruby is a green threaded application.  ie., irrespective of how many threads are running in the Ruby VM, there is only one operating system thread that the Ruby interpreter is scheduled on.  Needless to say, this seriously limits the concurrency achievable with one Ruby VM - and quite naturally drives deployments to operate herds of web servers for their application, front ended by load balancers(like Pen, Pound etc.,) and deployed in an automated fashion(with the likes of Capistrano) - JRuby is way better at threading, though not as good as one would expect(see comments below for a clarification).

 So why use --enable-pthread to configure/build Ruby?  

 Probably because building Ruby with support for a threaded extension(like Tcl/Tk on Solaris, which is compiled with support for pthreads) gives out a dire warning that compiling a threaded extension with a non-pthreaded Ruby will cause frequent crashes?  Now that could potentially happen if the threaded extension changed the interpreters context and left it in an inconsistent state, but in practice that turns out not to be true(write a threaded extension and run it through a Ruby interpreter that is not pthread enabled to verify).  

 Using --enable-pthread has performance ramifications.  In Ruby 1.8.6(which is still the sweet spot version in terms of security / stability) removing this option gives about a 2x boost in performance - this is due to the elimination of many getcontext and setcontext calls in the interpreter - these high overhead system calls are not used in the non-pthread enabled code, and avoiding pthreads does not impose a concurrency issue since Ruby is green threaded.  further, using --enable-pthread increases the size of Ruby's stack to the point that the compiler has to use a more complicated algorithm(as opposed to simply decrementing the stack pointer) for alloca, further increasing the interpreters overhead. 

 It's a good practice to avoid using --enable-pthread for Ruby 1.8.6.

Wednesday Oct 08, 2008

Correct way to install the MySQL gem -

A note by Mandy on the right way to install the MySQL gem on OpenSolaris -

Friday Aug 22, 2008

Rails2/Ruby/OpenSolaris on the Cloud

We just put up a Rails2 image running OpenSolaris on EC2.

This is the real deal, Rails2, Ruby with DTrace support, Thin, Git, Mongrel, Mongrel cluster, sample SMF scripts and configured for a sample Rails application, OpenSolaris with ZFS on the root disk,  MySQL, and Postgres.

OpenSolaris includes the Image Packaging System(IPS) which makes it trivial to add more software to the system.(for example, need AMP? just utter "pkg install amp-dev" )

It's available here

Monday Jun 02, 2008

Where's my Ruby?

OpenSolaris is different from Solaris Expresses(ie., the SXCE and SXDEs) in that most of the software that comprises this release is not distributed in the CD media(or image that can be downloaded from

There's just one CD, and rest of the packages that comprise OpenSolaris are hosted on, and available through the "/usr/bin/pkg" command.

Ruby is not on the base CD image, but to have a usable version of Ruby on OpenSolaris 2008.05 is very easy, just issue the following commands.

-bash-3.2#pkg install SUNWruby18


Completed 1/1 1546/1546 8.50/8.50


Install Phase 1844/1844

-bash-3.2# which ruby


-bash-3.2#pkg install SUNWgcc


Completed 4/4 2035/2035 88.13/88.13


Install Phase 2457/2457

-bash-3.2#cd /usr/ruby/1.8/lib/ruby/1.8/i386-solaris2.11

-bash-3.2#mv rbconfig.rb rbconfig.rb.orig


After this point, one is set to install Ruby applications with C extensions . . . like Mongrel or Thin.

Monday May 19, 2008

How to install Mongrel, Mysql, and Postgres gems in OpenSolaris Ruby -

Rubygems is the preferred package manager for Ruby, and Ruby packages are called gems. While most of the gems out there are written in Ruby, there are a few that have C or C++ code in them for performance(like Fastthread for Mongrel), or Features(like the MySQL connector for Ruby).
Such gems need a C/C++ compiler to successfully be installed. Apart from that, they also need an appropriately configured rbconfig.rb file in the Ruby installation.
The rbconfig.rb file is typically present in lib/ruby/site_ruby/1.8/rubygems.rb - on OpenSolaris, it is present as /usr/ruby/1.8/lib/ruby/site_ruby/1.8/rubygems.rb
The rbconfig.rb file contains, among other things, information about which compiler(ie., the location) was used to build Ruby, compiler flags, linker flags, path to the C++ compiler, location of ginstall etc.,
This is strictly not necessary for C applications, ie., you can install a native gem compiled with CompilerB on a version of Ruby that was compiled with CompilerA, but the advantage of having the build time compiler flags captured is that you can optimize the extensions just as the Ruby binary was optimized(and the folks who built Ruby for you hopefully have done some reasearch in this area).
On OpenSolaris, there's a bug by which some paths in the rbconfig.rb file actually point to a compiler location that was used by the build infrastructure, and this location is normally not present on the system.
This is a bug that is being fixed, and the right paths should work out of the box. Until that fix shows up in the repository, here's how to make sure your Ruby installation works well.

If you have Sun Studio installed on the machine, use this rbconfig.rb to use Studio(it assumes you've installed Studio into /opt/SUNWspro - which is where it goes into, by default).

If you prefer gcc, use this rbconfig.rb instead (it assumes gcc is in /usr/sfw/bin/gcc - which is a symlink from /usr/bin/gcc).

After you've replaced the original rbconfig.rb file, installing native gems should be easy.
If you used the gcc version, then all you have to do is utter "gem install mysql -- --with-mysql-dir=/usr/mysql/5.0", "gem install postgres", or "gem install mongrel" to install these packages.
Note that the "--with-mysql-dir" option is necessary. OpenSolaris has two versions of MySQL, the ancient version(4.x.y) is in the default link path, which you don't want to link to, MySQL 5.x.y is in /usr/mysql/5.0

Also, I assumed that Sun Studio is in it's default path of /opt/SUNWspro. The rbconfig.rb files are for Solaris running on an x86/x64 platform. If you're using SPARC, modify your file with appropriate values for INSTALL, CC, CFLAGS, CPPFLAGS, LDFLAGS, and CPP from my files.

Sunday May 11, 2008

Ruby 1.9 very first impression

Program: ruby -e 'require "benchmark"; p Benchmark.realtime { a=0;1000000.times {a = a + 1}; p a} '

On a machine running OpenSolaris on AMD Opteron. The timings are:

x64 Ruby 1.8.6: 1.31seconds
x64 Ruby 1.9: 0.198 seconds

I'll want to run programs that aren't as simplistic, of course, but still, wow! that's an 84% improvement for this loopy.

Wednesday Mar 26, 2008

DTrace support for Ruby

DTrace probe support is now into OpenSolaris - as of build 87. Siva, an engineer in my little Ruby team checked it into the free software gate last Tuesday night.

Pretty cool!

DTrace is a great way to profile Ruby programs without introducing much overhead into the program you're tracing. This is a real boon considering that overhead is a big problem with Ruby profilers today.

Also, you don't need to make _any_ changes to your Ruby programs in order to narrow your profile to a set of functions.

DTrace rocks.

Below is an example of how to use DTrace to profile Ruby programs. The program traces through method invocations in different classes, and indents nested invocations accordingly.

Here's the program:

[root@dn10 dtrace]$cat rb_funcalls.d 
#!/usr/sbin/dtrace -Zqs
 \* How do you invoke this script?
 \* Use dtrace -xbufsize=40m -Zqs rb_funcall.d -c "ruby my_arg1 my_arg2"
 \* Where "ruby" is DTrace enabled.

 \* Thread local variable to
 \* store the indentation level
 \* during/after a function call.
 self int indent;

    printf("Starting to trace\\n");

    \* To ensure that we capture function
    \* entries and returnes made by a thread
    \* in order.
    self->thread = 1;
    self->indent += 2;
    printf("%\*s", self->indent, " ");
    printf("=> %s->%s\\n", copyinstr(arg0), copyinstr(arg1)); 
   printf("%\*s", self->indent, " ");
   printf("<= %s->%s\\n", copyinstr(arg0), copyinstr(arg1));
   self->indent -= 2;

   printf("Finished tracing\\n"); 
[root@dn10 dtrace]$

There are a couple of ways to invoke this - either start a process through the DTrace command line, or attach to an existing Ruby process. We'll do the latter since our program is rather simple.

[root@dn10 dtrace]$cat /tmp/hello.rb
message ="Hello World")
puts message
[root@dn10 dtrace]$

On uttering the appropriate DTrace mantra, the following ensues:

[root@dn10 dtrace]$dtrace -xbufsize=40m -Zqs rb_funcalls.d  -c "ruby /tmp/hello.rb"
Starting to trace
Hello World
  => Class->new
    => String->initialize
    <= String->initialize
  <= Class->new
  => Object->puts
    => IO->write
    <= IO->write
    => IO->write
    <= IO->write
  <= Object->puts
Finished tracing

A few comments about the invocation and the scripts are in order here. You don't need a very high value of xbufsize for a small data set, it's just illustrative. You really need the -Z option because it ensures that DTrace doesn't bail out with complaints that it couldn't find the ruby\*:::function-return(and other) probes. DTrace would otherwise do that when dealing with application level probes.
Moving to the script, note that it address the probes as "ruby\*". This means that the selected probes in all Ruby processes running on your system will be activated and profiled, not just in the command you just invoked. If you don't like that, and instead want to trace a specific process, two changes are in order:
1. In the script, change "ruby\*" to "ruby$1"
2. when calling the script - use "dtrace -xbufsize=40m -Zqs rb_funcalls.d my_pid" . Where "my_pid" is the pid of the Ruby process you're interested in profiling.
You can obtain more data from the probes, such as the source file being interpreted, and the line number. Use arg2 and arg3. An example of how to use them is:

#!/usr/sbin/dtrace -Zqs

    printf("Class name: %s, Method name %s, Source file %s,  Line number %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);

To invoke the above script, just utter "dtrace -xbufsize=40m -Zqs rb_fn_info.d", and assuming that you have a ruby process already running in your system - you'll begin to see data like the below.(else use the -c option to launch a command. Or use ruby$1 and a command line argument for the pid that you'd like to latch on to)
Class name: Proc, Method name call, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/ruby-lex.rb,  Line number 207
Class name: IRB::Context, Method name prompting?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 115
Class name: IRB::Context, Method name verbose?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/context.rb,  Line number 156
Class name: NilClass, Method name nil?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/context.rb,  Line number 144
Class name: Object, Method name kind_of?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/context.rb,  Line number 145
Class name: IO, Method name tty?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/context.rb,  Line number 156
Class name: Object, Method name kind_of?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/context.rb,  Line number 156
Class name: Object, Method name kind_of?, Source file /usr/ruby/1.8/lib/ruby/1.8/irb/context.rb,  Line number 157
Class name: IRB::Irb, Method name prompt, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 116
Class name: Object, Method name dup, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 266
Class name: String, Method name initialize_copy, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 266
Class name: String, Method name gsub!, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 267
Class name: Object, Method name ===, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 269
Class name: String, Method name ==, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 269
Class name: Object, Method name ===, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 269
Class name: String, Method name ==, Source file /usr/ruby/1.8/lib/ruby/1.8/irb.rb,  Line number 269

And that's all it takes to get dangerous. You can of course do a lot of fancy profiling with all these(and I'll save that for a different entry, since I've got to get to bed in time for an early morning phone call ;-)

Tuesday Mar 18, 2008

Doing The Right Thing, or Why Rails is not in OpenSolaris

If you haven't been watching the discussion on, the news is that Rails will not be integrated with OpenSolaris or Nevada.
ie., an installation of SXCE/SXDE/Nevada/Indiana will have Ruby installed, but Rails will not be available by default.

The recommended way to install Rails and other gems is by using the gem command - using the famous utterance "gem install rails --include-dependencies".
And that's it.

I think this is the right position for us to take. I think it's quite a brave one, and one that shows that we are truly working as a community now, at least in my corner of the universe.
Think about it . . . with other OSes drawing users away from Ruby's native packaging, in order to "do it their way" - what would the natural response from an operating system vendor be? To say "Let it be, a good solution already exists in Rubygems", or "hey, we want XYZ library delivered through our mechanism, irrespective of what the problems are"?

Rubygems is the chosen package manager for Ruby, and abiding by that decision helps Ruby users on Solaris - and people get that. We got a a lot of comments from our user community, as well as from the good folk at Twitter about Solaris packaging for Ruby gems in general - and nobody at Sun, after having heard the story, ever said, "you know, Debian has it, BSD has it, so we should do it too".

And that's a brave step to take.

Thanks to all the folk that provided comments, please keep them coming, and I'm proud of the folk at Sun, for working sincerely with the community.

Friday Feb 15, 2008

SXDE 1/08: First Solars Release that includes Ruby

SXDE 1/8(or the more wordy Solaris Express Developer Edition 1/8) was released two weeks ago, and this is the first Solaris release to have the Ruby programming language available as an operating system feature.

Expect to find it as /usr/ruby/1.8/bin, and linked from /usr/bin/ruby. We used the /usr/ruby/1.8 location to be friendly to different Ruby versions. ie., when version 1.9 comes out, expect to find it in /usr/ruby/1.9/bin.

Rubygems is also included in this release. So that should make it quite simple to be up-and-running with Ruby development . . . did I hear you ask about an IDE?
Well, the famous Netbeans, with built-in Ruby support, is available in Solaris express. Netbeans has been getting so many good reviews these days for it's Ruby support. This release allows you to choose between the native Ruby and jruby for your projects . . . cool.

What's on the roadmap?

Now that we have the Ruby platform, extensions, and Rubygems - the next step is to integrate the Rails stack.
This should also be available as IPS packages for OpenSolaris Indiana.

DTrace support should be available earlier than that, and Gems for MySQL and Postgres should be available along with Rails.

Expect to see these components go into the Solaris Express Community Edition(or Nevada) builds in the near future.

Oh, if you need Ruby/Rails for Solaris 10 - then use Coolstack. This doesn't come with the OS, but needs you to execute a simple pkgadd command to install it. It installs Ruby into /opt/coolstack.




« June 2016