Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ddollar
Created October 19, 2011 16:53
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ddollar/fe7f04abbd9538b656c5 to your computer and use it in GitHub Desktop.
Save ddollar/fe7f04abbd9538b656c5 to your computer and use it in GitHub Desktop.
Creating a Heroku Buildpack

What is a Buildpack ?

A buildpack is an adapter between an app and Heroku's runtime. A buildpack is responsible for language/framework-specific details including:

  • Creating the proper runtime environment around the app (e.g. installing node into the slug)
  • Dependency resolution (e.g bundle install, npm install)
  • Tweaking the app for Heroku's platform (e.g. forcing logs to go to stdout)

Getting Started

Modify an Existing Buildpack

We recommend building your buildpack on Github which will provide you with an easy public git URL to use for testing. To use a private repository you will need to embed a valid Github username and password into the URL.

Using a Github account, go to http://github.com/heroku/heroku-buildpack-hello and click the "Fork" button to create your own copy of this example buildpack..

Let's make a small change. On your fork, go to the bin/detect script, click "Edit this file", change the name HelloFramework to GoodbyeFramework and commit.

Using Your Buildpack

Create a Cedar app to test your buildpack:

:::term
$ cd myapp
$ heroku create -s cedar --buildpack http://github.com/YOURNAME/heroku-buildpack-hello.git
Creating sharp-rain-871... done, stack is cedar
http://sharp-rain-871.herokuapp.com/ | git@heroku.com:sharp-rain-871.git
Git remote heroku added

The buildpack will be used the next time you push the app.

:::term
$ git push heroku master
-----> Heroku receiving push
-----> Fetching custom buildpack... done
-----> GoodbyeFramework app detected
-----> Found a hello.txt
-----> Discovering process types
       Procfile declares types          -> (none)
       Default types for HelloFramework -> hello
-----> Compiled slug size is 4K
-----> Launching... done, v6
       http://test-hello.herokuapp.com deployed to Heroku

Congratulations, you now have your very own Heroku buildpack.

For an example of a non-trivial buildpack, see the Node.js buildpack.

Buildpack API

The following is a reference for the buildpack API.

A buildpack consists of three scripts:

bin/detect

Usage

bin/detect BUILD_DIR

Summary

This script takes BUILD_DIR as a single argument and should return an exit code of 0 if the app present at BUILD_DIR can be serviced by this buildpack. If the exit code is 0, the script should print a human-readable framework name to stdout.

Example

:::bash
#!/bin/sh

# this pack is valid for apps with a hello.txt in the root
if [ -f $1/hello.txt ]; then
  echo "HelloFramework"
  exit 0
else
  exit 1
fi

bin/compile

Usage

bin/compile BUILD_DIR CACHE_DIR

Summary

This script performs the buildpack transformation. BUILD_DIR will be the location of the app and CACHE_DIR will be a location the buildpack can use to cache build artifacts between builds.

All output received on stdout from this script will be displayed to the user.

Build pack developers are encouraged to match the Heroku push style when displaying output.

:::bash
-----> Main actions are prefixed with a 6-character arrow
       Additional information is indented to align

Whenever possible display the versions of the software being used.

-----> Installing dependencies with npm 1.0.27

Example

:::bash
#!/bin/sh

indent() {
  sed -u 's/^/       /'
}

echo "-----> Found a hello.txt"

# if hello.txt has contents, display them (indented to align)
# otherwise error

if [ ! -s $1/hello.txt ]; then
  echo "hello.txt was empty" | indent
  exit 1
else
  echo "hello.txt is not empty, here are the contents" | indent
  cat $1/hello.txt | indent
fi

bin/release

Usage

bin/release BUILD_DIR

Summary

This script returns a YAML formatted hash with three keys:

  • addons is a list of default addons to install
  • config_vars is a hash of default config vars to use. These will only be applied the first time the buildpack is used for each app.
  • default_process_types is a hash of default Procfile entries for this buildpack.

Example

:::bash
#!/bin/sh

cat << EOF
---
addons:
  - shared-database:5mb
config_vars:
  PATH: bin:/usr/bin:/bin
default_process_types:
  hello: cat hello.txt
EOF

Caching

Use caution when storing large amounts of data in the `CACHE_DIR` as the full contents of this directory must be transferred over the network each time this app is deployed. A large `CACHE_DIR` can introduce significant delay to the build process.

The bin/compile script will be given a CACHE_DIR as its second argument which can be used to store artifacts between builds. Artifacts stored in this directory will be available in the CACHE_DIR during successive builds. CACHE_DIR is availble only during slug compilation, and is specific to the app being built.

Build packs often use this cache to store resolved dependencies to reduce build time on successive deploys.

Bundled Binaries

Use [Vulcan](http://github.com/heroku/vulcan) to easily build binaries that are compatible with the Heroku runtime. [http://github.com/heroku/vulcan](http://github.com/heroku/vulcan)

A buildpack is responsible for building a complete working runtime environment around the app. This may include language VMs and other runtime dependencies that are needed by the app to run.

These binaries should be kept in versioned tarballs on S3 and downloaded by the buildpack during compile. For example, the Node.js buildpack may download from a URL like http://heroku-buildpack-nodejs.s3.amazonaws.com/node-0.4.7.tgz

See the Node.js Buildpack to see how this is done.

Example Buildpacks

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