We have previously demonstrated adding Pharo to Cloud Foundry. Since that time Cloud Foundry has been substantially revised and the process for adding a runtime/framework has changed to be based on a buildpack model. In general, this makes things easier but there are some complications.

On the Server

To deploy a Pharo application to Cloud Foundry we log in to the private Cloud Foundry instance created earlier. So that I can set the shell title and not have it replaced I typically change the prompt:

export PS1='\[\e[0;35m\]\h\[\e[0;34m\] \w\[\e[00m\]$ '

By default, Cloud Foundry is set up to run 64-bit applications. In order to run the 32-bit version of Pharo we need to add some libraries:

sudo apt-get install -y ia32-libs

As discussed in the architecture documentation, each application runs in a container with a private root filesystem. Thus, the 32-bit libraries need to be added to the shared read-only portion. This should be done using the general Cloud Foundry install scripts, but as a first attempt I’m just doing it manually:

cd /var/vcap/data/packages/rootfs_lucid64/0.1-dev
sudo rsync -r -l -D -g -o -p -t /lib32 . # 12 MB
sudo rsync -r -l -D -g -o -p -t /usr/lib32 ./usr/ # 153 MB
sudo cp /lib32/ld-linux.so.2 ./lib/
cd usr/lib
sudo rsync -r -l -D -g -o -p -t /usr/lib/libv4l* .
sudo rsync -r -l -D -g -o -p -t /usr/lib/gio .
cd gtk-2.0/
sudo rsync -r -l -D -g -o -p -t /usr/lib/gtk-2.0/i* .
cd 2.10.0/
sudo ln -s ../../../lib32/gtk-2.0/2.10.0 i486-pc-linux-gnu
sudo ln -s ../../../lib32/gtk-2.0/2.10.0 i686-pc-linux-gnu

I’m not sure that all of the above is necessary, but it seems to be sufficient to run Pharo as a runtime in a container. Next, we install Pharo and make it visible (with the same recognition that this could be done better using the install scripts):

sudo mkdir /opt/pharo
cd /opt/pharo
sudo chmod 777 .
curl http://files.pharo.org/vm/pharo/linux/Pharo-VM-linux-stable.zip > pharo.zip
sudo unzip pharo.zip; rm pharo.zip
sudo chmod 755 .
cd /var/vcap/data/packages/rootfs_lucid64/0.1-dev/opt
sudo rsync -r -l -D -g -o -p -t /opt/pharo .

Now we get to the part of making a Pharo buildpack. Eventually this should be in a Git repository but for now I’ll just add it directly to my private Cloud Foundry instance so that it looks like a built-in buildpack.

cd /var/vcap/packages/dea_next/buildpacks/vendor
mkdir pharo pharo/bin; cd pharo; git init
cat > README.md << EOF
Cloud Foundry Buildpack for Pharo Smalltalk
==============
EOF

The actual buildpack consists of three files that are called by Cloud Foundry, all in the bin directory. First is bin/detect (use an editor to create these files):

#!/usr/bin/env bash
#
if [ -f $1/*.image ]; then
 echo "pharo" && exit 0
else
 echo "no" && exit 1
fi

This will confirm that the Pharo buildpack can handle an application that contains a .image file. Next we create bin/compile to add a startup script to the application:

#!/usr/bin/env bash
#
BUILD_DIR=$1
CACHE_DIR=$2
BUILD_PACK_DIR=$(dirname $(dirname $0))
#
if [ ! -d "$BUILD_DIR" ]; then
 mkdir -p "$BUILD_DIR"
fi
#
if [ ! -d "$CACHE_DIR" ]; then
 mkdir -p "$CACHE_DIR"
fi
#
cat > "$BUILD_DIR/startup.sh" << EOF
#!/usr/bin/env bash
IMAGE=\`ls *.image\`
STARTUP=\`ls | grep startup.st\`
/opt/pharo/pharo -vm-display-null -vm-sound-null \$IMAGE \$STARTUP
EOF
chmod +x "$BUILD_DIR/startup.sh"

Third, we create bin/release to return a YML file with startup information:

#!/usr/bin/env bash
#
cat <<EOF
---
default_process_types:
 web: ./startup.sh
EOF

Finally, we set these three files to be executable:

chmod +x bin/*

Now that we have modified our private Cloud Foundry instance support Pharo we start it up:

cd ~/cf_nise_installer/; ./local/start_processes.sh

It seems that the startup might need a bit of extra time. To check on the status do the following:

sudo /var/vcap/bosh/bin/monit summary

On the Client

In our previous approach to adding Pharo to Cloud Foundry, we went to some effort to avoid copying the image, changes, and sources files over the network from the client to the server (because they are typically quite large). That earlier approach, while elegant, is a bit less obvious to application developers who just want to deploy their application. In this iteration I’ve taken the approach of doing the simplest thing and waiting till it causes a problem to “improve” things. Thus, we expect you to provide the image file and we will just run it. The primary thing that you have to do is modify your code to provide a web server on the port defined in the $PORT environment variable (which can be different each time the application is launched). To facilitate this you can include a ‘startup.st’ script in your directory that will be run each time the application starts. This allows you to change the listening port each time. Following is a sample ‘startup.st‘ script that we use with an AIDAweb one-click image:

| methodSource port |
methodSource := 'introductionElement
 | element |
 element := WebElement new.
 element addText: self observee introduction.
 element addText: ''<p>Listening on port: '' , 
 session parent site port printString , ''</p>''.
 ^element'.
Author fullName: 'CloudFoundry'. "Developer's name"
WebDemoApp compile: methodSource.
port := OSProcess thisOSProcess environment at: #'PORT' ifAbsent: ['8888'].
AIDASite default
 stop;
 port: port asNumber;
 start.

At this point we can connect to our private cloud and push the application:

cf target api.172.16.217.185.xip.io # use the IP address of your private cloud
cf login --password micr0@micr0 micro@vcap.me
cf create-space development 
cf target --space development
cf map-domain mycloud.local
cf push
# Name> myapp
# [accept defaults]
# Save configuration?> y

Now, make sure that ‘myapp.mycloud.local’ is in your /etc/hosts file and points to your private cloud. Then you can open a web browser on http://myapp.mycloud.local and you should see your application running!

As you think about running a Pharo application in the cloud, remember that the file system is ephemeral. That is, your application can be restarted any time and changes made to the image will not be saved. See http://docs.cloudfoundry.com/docs/using/app-arch/ for a good discussion of some architectural issues.

Advertisements