Deploy a Go Web App to the Swisscom Application Cloud

Inspired by the this blog post about the deployment of a node.js example app to the Swisscom Application Cloud, I decided to test the Swisscom Application Cloud my self with a similar app, written in Google Go language.

This blog should take you through the essential steps on a Linux based system to push your own Go based app to a Cloud Foundry based app cloud, for example the one from Swisscom.

Preparations

Go development environment

I assume you already have a prepared Go development environment. Otherwise I suggest you to start with the Getting Started manual.

To check, if you have the go tool chain ready, just enter

go env

this should print something like the below

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/user/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GO15VENDOREXPERIMENT="0"
CC="gcc"
GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread"
CXX="g++"
CGO_ENABLED="1"

If you are using Go in version 1.5.x, you may have set the environment variable GO15VENDOREXPERIMENT=1. For this tutorial I suggest to switch the Go 1.5 vendor experiment off (GO15VENDOREXPERIMENT=0), as this makes our deployment to the app cloud a little bit easier. (Additional information about the hitches with godep and the Go 1.5 vendor experiment could be found in this article on heroku.)

Godep

Cloud Foundry uses so called buildpacks to provide framework and runtime support for the application. We will later use the Go buildpack to deploy our web app to the app cloud.

In order to specify the external dependencies (external Go packages) for the Go web app, the above mentioned buildpack uses the tool Godep.

The installation of Godep is quite straight forward. Just let Go do the work for us:

go get github.com/tools/godep

This will place the godep command in the directory $GOPATH/bin. If $GOPATH/bin is part of your $PATH, godep is now directly available as command.

Cloud Foundry CLI

The Cloud Foundry Command Line Interface (CF CLI) is a command line tool for deploying and managing your applications within the app cloud. You can download the CF CLI from github.com/cloudfoundry/cli/releases.\

The CF CLI tool is written in Go as well and therefore consists of a single static binary. The installation is as simple as download and decompress the executable. For a 64 bit Linux systems, you could use the following commands to download the latest version (6.14.0 as of writing) and to place the executable to the current directory.

curl -L 'https://cli.run.pivotal.io/stable?release=linux64-binary&version=6.14.0&source=github-rel' | tar -xz > cf; chmod +x cf

To check if everything is working, execute ./cf help. For best comfort, you should move the cf binary to a directory within you $PATH.

Alternatively there are installable packages for several OS available as well.

Create the Go “Hello world” Web App

Now we have everything in place to get started with writing the Go version of the “Hello world” web app.

First you should create a new directory named appcloud within $GOPATH/src and enter it. If you are a github.com user, a good choice would be $GOPATH/src/github.com/<your github username>/appcloud. Secondly create a new file named main.go with the following content:

package main

import (
  "fmt"
  "log"
  "net/http"
  "os"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello world!")
}

func main() {
  port := os.Getenv("PORT")
  if port == "" {
    port = "3000"
  }

  log.Printf("Use port: %s\n", port)

  http.HandleFunc("/", helloHandler)
  err := http.ListenAndServe(":"+port, nil)
  if err != nil {
    log.Panicf("ListenAndServe error: %v\n", err)
  }
}

This program is quite straight forward:

That’s it for the web app. Now let’s have a look, if every thing is working properly.

We can start our web app with the following command:

go run main.go

Just after starting you should see an output similar to the one below:

2015/12/17 10:58:38 Use port: 3000

If no other output is printed out, the program is ready to serve HTTP requests. So point your web browser to http://localhost:3000 and enjoy the “Hello world!” output.

Move into the Cloud

Before we can move our newly build Go based web app to the Swisscom App Cloud, we have to do some preparations:

  1. Setup a Swisscom Developer Account
  2. Specify our dependencies with Godep
  3. Create a Cloud Foundry manifest.yml
  4. Upload everything to the cloud

Setup a Swisscom Developer Account

I don’t go into all the details, because they are already outlined in this blog post. For the brave, just head to Swisscom Developer Account and follow the instructions (you will need a credit card in order to precede).

Specify our Dependencies with Godep

Even if we don’t use any external dependencies, because all used packages belong to the Go standard library, the file, describing the dependencies for our program has still to be present.

This file is auto generated with the command godep save -r (assuming the godep command resides within the $PATH). This will create a new directory named Godeps. Within this directory we find a file called Godeps.json with a content like to following:

{
  "ImportPath": "github.com/breml/appcloud",
  "GoVersion": "go1.5.2",
  "Deps": []
}

If you have a properly setup $GOPATH and your web app for the app cloud is placed within the $PATH/src/, everything should be fine.

If this is not the case, for whatever reason you have to manually modify the just generated Godeps/Godeps.json file in order to work with the Go buildpack. Most likely the line with ImportPath reads as follows:

"ImportPath": ".",

In this case the “.” has to be replaced with the directory name, where your go web app resides. If you have followed the instructions above, your directory is named appcloud and you have to replace the above line with:

"ImportPath": "appcloud",

Create a Cloud Foundry manifest.yml

From the Cloud Foundry docs we learn about manifest.yml:

The application manifest tell the cf push command what to do with applications. This includes everything from how many instances to create and how much memory to allocate to what services applications should use.

For our small Go web app, we need to provide the following information within the manifest.yml:

---
applications:
- name: DemoApp
  memory: 64M
  host: demoapp<YOURNUMBER>
  buildpack: https://github.com/cloudfoundry/go-buildpack.git
  command: appcloud

In detail:

Upload Everything to the Cloud

Now with everything set, we may login at the Swisscom App Cloud with:

cf login -a https://api.lyra-836.appcloud.swisscom.com

and finally deploy our application:

cf push

If everything is successful, you may now access your “Hello world” app at http://demoapp&lt;YOURNUMBER&gt;.scapp.io/.

Annex

An extended version of the example, described in this blog post, may be found on github.com/breml/appcloud. Commit dcb5ce9d does correspond to this post.

In the original post you may find information about scaling your app and combining your app with services.

Updates

17.12.2015

Just found out, Go version 1.5 is not supported by the buildpack. Therefore we have to provide the Go version in Godeps/Godeps.json including the minor version (1.5.1 or 1.5.2) even though godep in the latest version suggests to only specify the major version of Go.

Warning by godep:

godep: WARNING: Recorded go version (go1.5.2) with minor version string found.
godep: To record current major go version run `godep update -goversion`.