Deploying a git subtree to Heroku (or other PaaS)

Most of the common PaaS platforms like OpenShift and Heroku deploy code based on a source in a git repo – you push your local repo containing source to the remote repo on the platform, the build is performed remotely and then deploys the built artifacts.

What if you want to deploy an app that is prebuilt, or you have a git repo that contains various subfolders, and only part of the folder structure in the repo is what you need deployed?

I’ve been experimenting with a simple React app that also has a node.js backend. In hindsight restructuring the source tree to make the app easier to deploy may have been simpler, but it turns out you can push part of your source subtree to a remote repo, like an application deployed to Heroku, using ‘git subtree’:

git subtree push –prefix subfoldername heroku master

This is discussed in this post here.

Managing SSH keys on Heroku

Heroku uses Git for your code repo, and therefore uses SSH to talk to the remote server. If you’re already using an SSH keypair for another repo or elsewhere, you may have to explicitly manage which of your key’s you want to use to access Heroku.

To list your current keys you’ve shared with Heroku:

heroku keys

To add a new key – run this from your ~/.ssh/ dir:

heroku keys:add keyfilename (e.g. rsa_id.pub)

If you get this error:

Fingerprint already exists. Please use one SSH key per Heroku account

… it’s because you’ve already used this SSH key with another account.

In a Nutshell: Deploying a Java webapp to Heroku

This post walks you through getting started with Heroku and deploying a simple Spring MVC web app.

  • Follow the Getting Started guide to get your Heroku Toolbelt setup
  • Login to Heroku from the commandline with ‘heroku login’
  • Since Heroku does not provide it’s own app server, you configure your pom.xml to pull in a dependency on a container, like Jetty (this is from the Getting Started with Spring MVC guide)
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>copy</goal></goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.mortbay.jetty</groupId>
                        <artifactId>jetty-runner</artifactId>
                        <version>7.4.5.v20110725</version>
                        <destFileName>jetty-runner.jar</destFileName>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

The Heroku Getting Started with Java instructions give some steps on how to run your app locally by running Java from the command line and passing a classpath pointing to your target dir, but this seems odd since Jetty is able to run from Mavan against your created war file or even the code compiled to your target dir using the ‘mvn jetty:run’ command. Add the following to the above <plugins> section to enable and use this approach instead:

<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
</plugin>

  • Heroku uses a file named ‘Procfile’ in the root of your project to tell Heroku how to run your code. Add this file, and inside it add this one line
web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war
  • Create your new app on Heroku with ‘heroku create –stack cedar’
  • Add and commit your code if you haven’t already, then push to your heroku remote git:
git add . git commit -m "commit comment" git push heroku master

At this point Heroku should build you app remotely and start it up.

If you see this error about the jetty-runner.jar missing, then you forgot to add the plugin part to your pom.xml to copy the jetty jar to the target/dependency dir:

Unable to access jarfile target/dependency/jetty-runner.jar