Skip to content

Instantly share code, notes, and snippets.

@AndreasMadsen
Last active February 13, 2022 16:15
Show Gist options
  • Star 34 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save AndreasMadsen/3732950 to your computer and use it in GitHub Desktop.
Save AndreasMadsen/3732950 to your computer and use it in GitHub Desktop.
Playing with smartos

Running SmartOS under vmware Fusion

From https://gist.github.com/3050224

From http://blog.smartcore.net.au/smartos-the-basics/

  1. Start by downloading the latest live image
  2. Save this file in a permanent place since your setup will need to boot from it permanently
  3. When you run the new VM wizard, select "Continue without disk" on the first screen of the wizard.
  4. Select Sun Solaris / Solaris 10 64-bit on the next screen.
  5. Now save the VM file and configure it (SmartOS requires very little, but you can go higher if you wish)
    1. Set the CPU to 1 core
    2. Set the Memory to 1024
    3. Advanced options - Enable hypervisor application in this virtual machine (This allows KVM support)
    4. Advanced options - Enable code profilling applications in this virtual machine (This is what we will do, right!)
  6. You're going to get dumped to a config screen when the live image starts up, choose DHCP for the networking and defaults for everything else.
  7. Pretty much the first thing you're going to want to do is figure out how to SSH into the box once it boots and creates its storage pools, because trying to do stuff in the virtual console is miserable. There's no cut and paste, and as far as I know there are no vmware tools for SmartOS. Because a bunch of this involves working with long UUIDs, you really want cut and paste (although try tab-completion -- I had some trouble with it a while ago, but @ryancnelson reminded me about it and it's working fine for me now).
    1. Run ifconfig -a and take a note of the e1000g0 interface's IP address (it'll be something like 172.xxx.xxx).
    2. In a Terminal / iTerm window, ssh root@<ip address>

Install pkgin

From http://wiki.smartos.org/display/DOC/Installing+pkgin

This is the SmartOS package manager you will find the latest version at http://pkgsrc.joyent.com/packages/SmartOS/bootstrap/ in this case its bootstrap-2013Q2-x86_64.tar.gz

cd /
curl -k http://pkgsrc.joyent.com/packages/SmartOS/bootstrap/bootstrap-2013Q2-x86_64.tar.gz | gzcat | tar -xf -
pkg_admin rebuild
pkgin -y up

Create Node.js image

From https://gist.github.com/3050224

From http://wiki.smartos.org/display/DOC/How+to+create+a+zone+%28+OS+virtualized+machine+%29+in+SmartOS

From http://stu.radnidge.com/post/30612112900

imgadm update
imgadm avail | grep base64
# copy the UUID "9eac5c0c-a941-11e2-a7dc-57a6b041988f" from the latest version (look at the date)
# Note there exist a node image too, but its always outdated and it contains software that you most likely don't need

imgadm import 9eac5c0c-a941-11e2-a7dc-57a6b041988f
# you should also see a ASCII progress bar. If instead you see:
#   60a3b1fa-0674-11e2-abf5-cb82934a8e24 doesnt exist. continuing with install
# you are mostlikely running an older SmartOS version, don't worry it is downloading it just dosn't show any progress

# /zones/ is the permanent directory if you store something elsewhere it will be deleted when SmartOS power off.
mkdir /zones/defs
touch /zones/defs/base.json

# dataset_uuid: the copied UUD
# nics[0].ip: In smartos I typed `ifconfig -a` and found `e1000g0` (172.16.136.129).
#   so for the SmartMashine I use `172.16.136.100` (I just picked 100 randomly)
# nics[0].gateway, resolvers[0]: I typed `netstat -r` and find the default gateway value (172.16.136.2).
# ram: My VM of smartos is given 1024 so I give my SmartMachine 512

echo '
{
  "brand": "joyent",
  "ram": 512,
  "autoboot": false,
  "dataset_uuid": "9eac5c0c-a941-11e2-a7dc-57a6b041988f",
  "resolvers": [
    "172.16.136.2",
    "8.8.8.8"
  ],
  "nics": [
    {
      "nic_tag": "admin",
      "ip": "172.16.136.100",
      "netmask": "255.255.255.0",
      "gateway": "172.16.136.2"
     }
  ]
}' > /zones/defs/base.json

vmadm create -f /zones/defs/base.json

Login to node.js SmartMashine

From http://stu.radnidge.com/post/30612112900

From https://gist.github.com/3050224

From https://help.github.com/articles/generating-ssh-keys

# this is in smartOS
mkdir /zones/keys
exit

# this is on your mac
scp ~/.ssh/id_rsa.pub root@172.16.136.129:/zones/keys/id_rsa.pub

# this is in smartOS
ssh root@172.16.136.129

vmadm list
# output:
# UUID                                  TYPE  RAM      STATE             ALIAS
# 463647dc-57f8-45ac-bdc2-18b0cc4c0be6  OS    512      running           -
# copy the UUID

vmadm start 463647dc-57f8-45ac-bdc2-18b0cc4c0be6
zlogin 463647dc-57f8-45ac-bdc2-18b0cc4c0be6
# you are now in SmartMashine

# setup ssh access for root
scp root@172.16.136.129:/zones/keys/id_rsa.pub ~/.ssh/authorized_keys

exit
exit

And then finally:

# ssh root@<SmartMachine IP>
ssh root@172.16.136.100

Repeated commands when starting smartOS VM

When starting the smartOS VM again you will need to do the following, before you can connect to the Node.js SmartMachine.

This is in VMware Fusion

Login on root

ssh root@172.16.136.129

# Start the SmartMashine
vmadm list
vmadm start 463647dc-57f8-45ac-bdc2-18b0cc4c0be6

exit

This is in a mac terminal

# ssh root@<SmartMachine IP>
# the IP address is static (it won't change)
ssh root@172.16.136.100

Install some basic packages

This might come in handy, and serve as an example on how to install a package using pkgin. The procedure is to do a pkgin search <name> and then find something that looks good copy the <longname> and type pkgin install <longname>.

ssh root@172.16.136.100

# install git, search for git
pkgin search git
pkgin install scmgit-1.8.1.5

# install gcc
pkgin search gcc
pkgin install gcc47-4.7.2nb3

# install make (gmake on SmartOS)
pkgin search gmake
pkgin install gmake-3.82nb5

# install binutils (a DTrace filter is in here)
pkgin search binutils
pkgin install binutils-2.22nb1

Updating Node.js

Node.JS will already be install but you are mostlikely not running the latest version, usually you can upgrade it with pkgin:

pkgin search node
pkgin install nodejs-0.10.15
# this will uninstall the old version and install the new one

In case pkgin don't contain the latest version you can build and install it manaully and its good to know how anyway:

From http://wiki.joyent.com/display/node/Installing+Node.js+on+a+Joyent+SmartOS+SmartMachine

# Login to SmartMashine
ssh root@172.16.136.100

# download and unpack source code
mkdir ~/src
cd ~/src
curl -O http://nodejs.org/dist/v0.10.15/node-v0.10.15.tar.gz
gtar -xpf node-v0.10.15.tar.gz

# install node.js
cd node-v0.10.15
./configure --with-dtrace --prefix=/opt/local/
gmake install

# check node version (should be node-v0.10.15)
node -v

exit

Create a Node.JS service

From http://wiki.joyent.com/display/node/Installing+Node.js+on+a+Joyent+SmartOS+SmartMachine

From http://docs.oracle.com/cd/E19963-01/html/821-1474/smf-template-5.html

# Login to SmartMashine
ssh root@172.16.136.100

# create a code directory
mkdir ~/code/

echo '
var http = require("http");

http.createServer(function (req, res) {
  res.end("Hello, world!");
}).listen(80, function () {
  console.log("Server ready at:", this.address());
});' > ~/code/server.js

# Start app
node ~/code/server.js

# Now in a browser on your mac go to
# http://172.16.136.100/
# You should now see "Hello, world!"

Then hit your SmartMachine IP and make sure it says Hello, world!

If anything is broken, now’s the time to fix it, because we’re about to dive into Solaris > service land.

Quote: wiki.joyent

If anything was good, quit the node program now.

Each service in SmartOS is managed by a manifest.xml file, we will create one of those.

# Login to SmartMashine
ssh root@172.16.136.100

echo '<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="hallo-world">
  <service name="site/hallo-world" type="service" version="1">

    <create_default_instance enabled="true"/>

    <single_instance/>

    <dependency name="network" grouping="require_all" restart_on="refresh" type="service">
      <service_fmri value="svc:/milestone/network:default"/>
    </dependency>

    <dependency name="filesystem" grouping="require_all" restart_on="refresh" type="service">
      <service_fmri value="svc:/system/filesystem/local"/>
    </dependency>

    <method_context working_directory="/root/code">
      <method_credential user="admin" group="staff" privileges="basic,net_privaddr"/>
      <method_environment>
        <envvar name="PATH" value="/opt/local/gnu/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/usr/sbin"/>
        <envvar name="HOME" value="/root"/>
      </method_environment>
    </method_context>

    <exec_method
      type="method"
      name="start"
      exec="/opt/local/bin/node /root/code/server.js"
      timeout_seconds="60"/>

    <exec_method
      type="method"
      name="stop"
      exec=":kill"
      timeout_seconds="60"/>

    <property_group name="startd" type="framework">
      <propval name="duration" type="astring" value="child"/>
      <propval name="ignore_error" type="astring" value="core,signal"/>
    </property_group>

    <property_group name="application" type="application">

    </property_group>


    <stability value="Evolving"/>

    <template>
      <common_name>
        <loctext xml:lang="C">node.js hello-world service</loctext>
      </common_name>
    </template>

  </service>

</service_bundle>' > ~/code/manifest.json

# add the manifest.json file
svccfg import -V ~/code/manifest.json

# start the hallo-world service
svcadm enable hallo-world

# now hit http://172.16.136.100 in your browser

# to disable a service run
svcadm disable hallo-world
# and you will se that http://172.16.136.100 no longer respons :)

# start again
svcadm enable hallo-world

exit

Creating your first FlameGraph

From: http://blog.nodejs.org/2012/04/25/profiling-node-js/ From: https://github.com/davepacheco/node-stackvis

# Login to SmartMashine
ssh root@172.16.8.100

# install node port of FlameGraph
npm install -g stackvis

# Start node app
svcadm enable hallo-world

# ask dTrace to capture node services
# Will run in 60 secs
dtrace -n 'profile-97/execname == "node" && arg1/{
    @[jstack(150, 8000)] = count(); } tick-60s { exit(0); }' > stacks.out

# Hit http://172.16.136.100 in your browser a lot!

# Filter out c++ land
c++filt < stacks.out > demangled.out

# then convert the dtrace.out file to graph.svg
stackcollapse < demangled.out > collapsed.out
flamegraph < collapsed.out > graph.svg

# Go back to your mac
exit

# copy the graph.svg file to your desktop
scp root@172.16.136.100:/root/graph.svg ~/Desktop/graph.svg

# Now open ~/Desktop/graph.svg in your browser
# enjoy!

End result is: http://jsbin.com/welcome/28297

Create your second FlameGraph

What you see in the first FlameGraph is just a lot v8:Internal in a few cases that dose mean something but in this case, its because the FlameGraph only shows what the CPU spends time on and not the network. So to get a more meaningful FlameGraph try an application there uses some CPU time.

For instance I was debugging the htmlparser2 Tokenizer and created a small script for the purpose.

# download the script
curl https://gist.github.com/AndreasMadsen/6130122/raw/5fd79c7e7dfb7648ec6f2f6f4cef696d25a282f9/htmlparser2.js > ~/code/htmlparser2.js

# now run the script (be sure that the node server in the first FlameGraph isn't running)
node ~/code/htmlparser2.js

# In another terminal run DTrace
dtrace -n 'profile-97/execname == "node" && arg1/{
    @[jstack(150, 8000)] = count(); } tick-60s { exit(0); }' > stacks.out
c++filt < stacks.out > demangled.out
stackcollapse < demangled.out > collapsed.out
flamegraph < collapsed.out > graph.svg

# Again copy the graph to your mac
exit
scp root@172.16.136.100:/root/graph.svg ~/Desktop/graph.svg

End result is: http://jsbin.com/onemug/2

@naisanza
Copy link

Thanks for the gmake comment!

@leoj3n
Copy link

leoj3n commented Jul 5, 2016

Thanks for the "Login to node.js SmartMashine" section!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment