Streamlining Zone Creation Thanks to ZFS Integration

Posted on September 28, 2006

Zone’s a wonderful and handy tools for developers and admins alike, but creating them can be a time consuming activity especially when you need to create more than one. Scripting can help but your not shortening the time, just automating the process. But around Nevada B43 ZFS and Zones were integrated, building on each others strengths. Now we can clone zones, which reduces the amount of wasted disk space when creating multiple zones that are initially identical. When you create a zone in a ZFS pool a new filesystem is automatically created instead of just a simple directory. And just in case your existing zones are on UFS and you want to migrate them to ZFS, you can use the handy move capabilities of zoneadm to move everything seemlessly for you.

Lets take a look at the process.

First lets create our initial zone, which I’m calling “puppet1”.

$ zonecfg -z puppet1 'create; set autoboot=true; set zonepath=/ultrastor/puppet1; add net; 
set address=10.0.0.21; set physical=nge0; end; verify; commit; exit'
$ zonecfg -z puppet1 info
zonename: puppet1
zonepath: /ultrastor/puppet1
autoboot: true
bootargs:
pool:
limitpriv:
inherit-pkg-dir:
        dir: /lib
inherit-pkg-dir:
        dir: /platform
inherit-pkg-dir:
        dir: /sbin
inherit-pkg-dir:
        dir: /usr
net:
        address: 10.0.0.21
        physical: nge0

Note in the above that by default /usr, /sbin, /lib, and /platform are loopback mounted rather than copied, which is the default behavior. If you wanted a “blank” configuration with no defaults set you could have specified create -b to zonecfg.

zonecfg only creates the metadata required for my zone to function, the zone itself hasn’t actually been created. So now I’ll go ahead and “install” the zone.

$ time zoneadm -z puppet1 install
A ZFS file system has been created for this zone.
Preparing to install zone .
Creating list of files to copy from the global zone.
Copying <35389> files to the zone.
Initializing zone product registry.
Determining zone package initialization order.
Preparing to initialize <1073> packages on the zone.
Initialized <1073> packages on zone.                                 
Zone  is initialized.
Installation of these packages generated warnings: 
The file  contains a log of the zone installation.

real    24m28.964s
user    1m0.522s
sys     1m50.353s

So that install took 25 minutes! Part of the hold up was due to my not inheriting /opt, and you see that in the output as the 35,000 files to copies. But because I want to write into /opt, it had to be done.

I personally can’t stand going through the sysid when you boot a zone for the first time (the curses interface that asks you all the questions), so I’ll insert a sysidcfg file before I boot the zone for the first time.

$ cat sysidcfg 
system_locale=C
timezone=US/Pacific
terminal=xterms
security_policy=NONE
root_password=HsANA7Dt/0sXX
timeserver=localhost
name_service=NONE
network_interface=primary {hostname=puppet1
        netmask=255.255.255.0
        protocol_ipv6=no
        default_route=10.0.0.250}
name_service=NONE
nfs4_domain=dynamic
$ cp sysidcfg /ultrastor/puppet1/root/etc/
$ zoneadm -z puppet1 boot

Against, this first boot is going to take a while as it initializes everything. While its booting you should watch the console by using zlogin -C puppet1 in another window.

So I’ve now spent the better part of an hour getting this zone setup and configured. At this point I can do any last little tweeks I want within the zone.

Now comes the real magic. I liked that first zone, but I need 4 more. Rather than repeat the process, I can simply clone them off! This first requires that I create the zone configuration for them.

$ zonecfg -z puppet2 'create; set autoboot=true; set zonepath=/ultrastor/puppet2; 
add net; set address=10.0.0.22; set physical=nge0; end; verify; commit; exit'
$ zonecfg -z puppet3 'create; set autoboot=true; set zonepath=/ultrastor/puppet3; 
add net; set address=10.0.0.23; set physical=nge0; end; verify; commit; exit'
$ zonecfg -z puppet4 'create; set autoboot=true; set zonepath=/ultrastor/puppet4; 
add net; set address=10.0.0.24; set physical=nge0; end; verify; commit; exit'

Now I can clone the first zone, puppet1, to bypass the normal “install” phase of the other zones.

$ zoneadm list -vc
  ID NAME             STATUS         PATH                          
   0 global           running        /                             
  19 puppet1          running        /ultrastor/puppet1                 
   - puppet2          configured     /ultrastor/puppet2            
   - puppet3          configured     /ultrastor/puppet3            
   - puppet4          configured     /ultrastor/puppet4   
$ zlogin puppet1 halt
$ time zoneadm -z puppet2 clone puppet1
Cloning snapshot ultrastor/puppet1@SUNWzone1
Instead of copying, a ZFS clone has been created for this zone.

real    0m53.895s
user    0m0.289s
sys     0m0.218s
$ zoneadm -z puppet3 clone puppet1
Cloning snapshot ultrastor/puppet1@SUNWzone2
Instead of copying, a ZFS clone has been created for this zone.
$ zoneadm -z puppet4 clone puppet1
Cloning snapshot ultrastor/puppet1@SUNWzone3
Instead of copying, a ZFS clone has been created for this zone.

You’ll notice that it created a new ZFS snapshot each time I cloned, I could have actually specified “-s SUNWzone1” after the first clone to continue using that single snapshot.

Now we look again at our zone list to see that we’ve changed state for those 3 new zones from “configured” to “installed”:

$ zoneadm list -vc
  ID NAME             STATUS         PATH                          
   0 global           running        /                             
   - puppet1          installed      /ultrastor/puppet1            
   - puppet2          installed      /ultrastor/puppet2            
   - puppet3          installed      /ultrastor/puppet3            
   - puppet4          installed      /ultrastor/puppet4    

Perfect. To avoid any additional configuration I’ll take that sysidcfg I created earlier, change the hostname, and then copy it in. Once thats done, start ’em up.

$ cp sysidcfg /ultrastor/puppet2/root/etc/
$ cp sysidcfg /ultrastor/puppet3/root/etc/
$ cp sysidcfg /ultrastor/puppet4/root/etc/
$ vi /ultrastor/puppet2/root/etc/sysidcfg
$ vi /ultrastor/puppet3/root/etc/sysidcfg
$ vi /ultrastor/puppet4/root/etc/sysidcfg
$ zoneadm -z puppet1 boot
$ zoneadm -z puppet2 boot
$ zoneadm -z puppet3 boot
$ zoneadm -z puppet4 boot

And we’re done! Cloning lets us really leverage that initial time we spent getting our zone right and relieves us of having to repeat it over and over. While creating that first zone might take 30 minutes or more, more can be created in minutes with ease. By using sysidcfg files as well we even further reduce the intervention on our part.

$ zoneadm list -vc | grep puppet
  23 puppet1          running        /ultrastor/puppet1            
  27 puppet2          running        /ultrastor/puppet2            
  28 puppet3          running        /ultrastor/puppet3            
  29 puppet4          running        /ultrastor/puppet4  

Just wrap some of this up in a script and things get even simpler. If you thought you were burning through your class C address space before, just watch your network admin cridge now!