GO applications and Cloud Foundry

Cloud Foundry is one of many options to host your applications. It is a PaaS originally developed by VMware, now governed by Cloud Foundry Foundation. Not going much into details about where, how and what as those information is publicly available I’ll focus here on how to host your GO applications on any Cloud Foundry installation including PCF or PWS.

There’s a known and recommended way to push GO applications. It is based on using GO buildpack. Very briefly, the buildpack takes all of your source code and dependencies (managed by godep), builds the binary and creates a droplet that is then distributed to CF nodes. The alternative approach I want to describe here is based on building the binary locally and push the binary instead of the source code. I’ll leave the discussion about the advantages or disadvantages of such approach to a reader as in my opinion it is a matter of preference and specific project requirements.

Buildpacks

To understand what we're going to do, first we need to cover the idea of buildpacks. As per the documentation "buildpacks provide framework and runtime support for your applications. Buildpacks typically examine user-provided artifacts to determine what dependencies to download and how to configure applications to communicate with bound services."

And the description continues: “When you push an application, Cloud Foundry automatically detects which buildpack is required and installs it on the Droplet Execution Agent (DEA) where the application needs to run.".

In our case, we’ll use a special buildpack, called “noop buildpack”. This buildpack (as its name suggests) does nothing. We don’t need any special logic to introspect our application and find out what language it is written in or which runtime it requires, because we know it is going to be a Linux x64 binary.

Application bootstrap

Now that we've effectively deactivated standard "boostrap" procedure that is added to an app if using any of the proper buildpacks, we need some other way to start our process. And we can, there's a special directory ".profile.d" that CF recognises and executes all the scripts found there, like "setenv.sh" described here. And this is exactly what we'll use to bootstrap the app. We'll create a new project with ".profile.d" directory containing a script called "start.sh".
.
└── .profile.d
    └── start.sh

I am sure a careful reader just realised that this is by no means GO specific. Any script can be executed there, for example a script to run a python http server for serving static pages (full example here):

The important part of the script is the “cd app”. During the staging process, all of your application artifacts that are pushed to Cloud Foundry are placed into the “app” directory as can be seen using “cf files APP_NAME” command:

% cf files static-files-demo
Getting files for app static-files-demo in org ************* / space development as *************@gmail.com...
OK

.bash_logout                              220B
.bashrc                                   3.6K
.profile                                  675B
app/                                         -
logs/                                        -
staging_info.yml                          168B
tmp/                                         -

GO application

Now I suppose all should be clear. We'll build local binary of our application. It does not really matter what method you use for managing dependencies, it can be godep, go.pkg or gb. Just make sure to build amd64 linux binary:
$ GOARCH=amd64 GOOS=linux go build APP

Then create a ".profile.d/start.sh” file with a content similar to this:

And push your application to CF using noop-buildpack:

$ cf push APP_NAME -b https://github.com/igm/noop-buildpack

Conclusion

This approach describes an alternative and not very often presented way to push application to Cloud Foundry. But in some situation this can be useful and really fast way to get your GO application running on Cloud Foundry or any of its flavours. The possible drawback is that it is assumed the PCF nodes run amd64 Linux OS (cflinuxfs2 derived from Ubuntu 14.04), which is true at this time, but does not need to hold true in the future.