Platform.sh aims to support your applications, whatever they may be. We've supported PHP, Python, Ruby, and Node.js for quite some time now. Golang support has also been available as a beta for over a year.
Why just beta all this time? It worked and ran fine, but there was a catch: The bane of every Go developer's existence, the GOPATH. Making the GOPATH design play nicely with a build pipeline that focused on your code, rather than on code in some fixed parent directory, wasn't easy. It was possible with some intricate Makefile dancing but it was never something we really felt comfortable calling fully supported.
Fortunately, the new release of Go 1.11 has solved that problem for us. Amongst its other improvements are support for Go modules. The link there has far more detail for Go developers, but in short Go dependencies can now be managed in almost the same way as in other dependecy-managed languages like PHP (Composer), Ruby (Bundler), or Node.js (npm). No GOPATH required!
Specifically:
- Dependencies can be specified in a separate file (
go.mod
), and don't have to be checked into Git. - Dependencies can be downloaded on the fly during build, reliably and repeatably.
- Everything is local-directory relative. No more GOPATH!
- Compiling Go is still embarrassingly fast.
I'm sold, how do I use it?
It's surprisingly easy now.
First, include a go.mod
file in your project. You can create one with go mod init
and then modify it yourself or have Go populate it for you based on your source code.
When you run go build
locally, it will generate a go.sum
file that is a hash of the code you've downloaded for later validation checks. Add both the go.mod
file and go.sum
file to Git.
Now you can setup your .platform.app.yaml
file like so:
name: app
type: golang:1.11
hooks:
build: |
go build -o bin/app
disk: 1024
web:
upstream:
socket_family: tcp
protocol: http
commands:
start: ./bin/app
locations:
/:
allow: false
passthru: true
That configuration says:
- Use the Go 1.11 container image.
- Use
go build
as normal in the build step; because the Go modules files are in Git it will detect them and use those to locate and download dependencies, then stick the resulting binary atbin/app
. (Feel free to change that output location if you want.) - At runtime, start the Go application we build and forward all requests of any kind to it.
If the Go app stops for any reason, Platform.sh will automatically restart it.
That's it that's all, you now have a working Go app on Platform.sh.
But wait, how do I wire Go to Platform.sh?
You do need to tell your HTTP server in Go what port to listen on. Fortunately, that's easy! We have a Go helper library available (which is now super easy to install with Go modules) that gives you a clean struct to access all of the Platform.sh-specific environment information you need, including the port. If you're using the net/http
web server from the standard library, it's as simple as:
package main
import (
"net/http"
psh "github.com/platformsh/gohelper"
)
func main() {
p, err := psh.NewPlatformInfo()
if err != nil {
panic("Not in a Platform.sh Environment.")
}
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
// ...
})
// Note the Port value used here.
http.ListenAndServe(":"+p.Port, nil)
}
And now your Go server will accept requests forwarded from Platform.sh. Beyond that, the sky's the limit.
Welcome, Gophers, to the joys of safely deploying on Friday!