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 firstname.lastname@example.org 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.