Chef Blogs

Running Habitat Apps on Cloud Foundry

Justin Carter | Posted on | Chef Habitat

Editors note: One thing that we seek to emphasize with Habitat is choice. Choose your language scaffolding, package your app, and then choose your platform for deployment. In order to provide our users with as many options as possible, we partner with experts on various platforms such as Stark & Wayne for Cloud Foundry support. The following article is a guest post from Justin Carter, a consultant at Stark & Wayne. Read below to learn more about how to package and deploy your application to Cloud Foundry with Habitat. Questions? Join us over on Slack.


Habitat is an Open Source project that allows you to package your apps in a Platform/Runtime agnostic way. This blog post discusses the recently added Cloud Foundry exporter that enables running Apps packaged in Habitat to run on Cloud Foundry.

Build the App

We’ll be using this demo app as an example.

First lets build the app inside the habitat studio:

$ git clone https://github.com/cloudfoundry-community/expresso.git
$ cd expresso
$ hab studio enter
[1][default:/src:0]# build .
(...)
[2][default:/src:0]# ls results/*.hart
starkandwayne-expresso-0.1.0-20170927132309-x86_64-linux.hart

Exporting the App

Now that the app has been built, we face the issue of configuring it via the Cloud Foundry injected environment variables. Habitat doesn’t support configuring via arbitrary environment variables. Rather it relies on the hab-CLI being able to talk to an API to push configuration changes. In a Cloud Foundry setting this won’t work because the habitat http-API wont be exposed to the Cloud Foundry user.

Another way of configuring habitat based Apps is via a .toml file that overrides the default application configuration. The Cloud Foundry exporter makes it possible to provide a mapping file that specifies how the environment variables should be rendered into the configuration .toml file.

[3][default:/src:0]# cat <<EOF >mapping.toml
> [app]
> port = "${PORT}"
> EOF
[4][default:/src:0]# hab pkg export cf starkandwayne/expresso ./mapping.toml
(...)
[4][default:/src:0]# exit

This will export 2 Docker images:

$ docker images
REPOSITORY                                  TAG                         IMAGE ID            CREATED             SIZE
starkandwayne/expresso                      cf-0.1.0-20170927132309     ed9e423b1ad8        11 seconds ago      170MB
starkandwayne/expresso                      0.1.0-20170927132309        05a01c4ecf99        22 seconds ago      167MB
starkandwayne/expresso                      latest                      05a01c4ecf99        22 seconds ago      167MB

The one with the cf- tag prefix is enabled to run on Cloud Foundry.

Running the App

In order to run the application you must be logged in with the cf-CLI to a Cloud Foundry instance that supports running Docker containers.

First we push the Docker container to dockerhub:

$ docker push starkandwayne/expresso:cf-0.1.0-20170927132309

Then we run it on Cloud Foundry:

$ cf push expresso -o starkandwayne/expresso:cf-0.1.0-20170927141758
(...)
$ cf app expresso
Showing health and status for app expresso in org test / space habitat as admin...

name: expresso
requested state: started
instances: 1/1
usage: 256M x 1 instances
routes: expresso.local.pcfdev.io
last uploaded: Sat 23 Sep 14:47:03 CEST 2017
stack: cflinuxfs2
docker image: starkandwayne/expresso:cf-0.1.0-20170927141758

state since cpu memory disk details
#0 running 2017-09-23T12:48:04Z 0.2% 44.7M of 256M 556K of 512M

Once the image has been downloaded and the container started, we should be able access it via our browser or curl:

$ curl expresso.local.pcfdev.io
<!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><h1>Express</h1><p>Welcome to Express</p></body></html>%

Gotcha

In order for this to work you must make sure that the primary port is exposed and exported in the habitat plan.sh.

pkg_origin=starkandwayne
pkg_name=expresso
pkg_version=0.1.0
pkg_scaffolding=core/scaffolding-node

pkg_exports=(
 [port]=app.port
 )
pkg_exposes=(port)

Other than adding the pkg_exports and pkg_exposes variables, the app is exactly the result of following the steps in this blog.