Build, Deploy And Run A Go Application

In our Hands-On section, we show how to deploy a Docker image file using Flyctl. The question we are going to answer here is how do we build that image.

The Hellofly Application

You can get the code for the example from the hellofly Github repository. Just git clone https://github.com/fly-examples/hellofly to get a local copy.

The hellofly application is, as you'd expect for an example, small. It's a Go application that uses the gin web framework. Here's all the code:

package main

import (
        "net/http"
        "strings"

        "github.com/gin-gonic/gin"
)

func main() {
        r := gin.Default()
        r.LoadHTMLGlob("templates/*")

        r.GET("/", handleIndex)
        r.GET("/to/:name", handleIndex)
        r.Run()
}

// Hello is page data for the template
type Hello struct {
        Name string
}

func handleIndex(c *gin.Context) {
        name := c.Param("name")
        if name != "" {
                name = strings.TrimPrefix(c.Param("name"), "/")
        }
        c.HTML(http.StatusOK, "hellofly.tmpl", gin.H{"Name": name})
}

The main function sets up the server after loading in templates for pages to be output. When a request comes in, the handleIndex function looks for a name and feeds that name to a template. The template itself is very simple too:

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<h1>Hello from Fly</h1>
{{ if .Name }}
<h2>and hello to {{.Name}}</h2>
{{end}}
</body>
</html>

We're using a template as it makes it easier to show what you should do with assets that aren't the actual application.

Building the Application

As with most Go applications a simple go build will create a hellofly binary which we can run. It'll default to using port 8080 and you can view it on localhost:8080 with your browser. So, the raw application works. Now to package it up for Fly.

Packaging with a Dockerfile

The Dockerfile controls how the application is composed and preserved in an image. All Docker images start with a basic image to build on. We'll be using the Go 1.13 Golang image from the Docker Official Images.

FROM golang:1.13 as builder

Then we copy the source code over.

WORKDIR /go/src/hellofly
COPY . .

And being modern Go, we get the Go platform to download the required modules and compile our application.

RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -v -o hellofly

This is a multistage docker file, so we prepare a new stage.

FROM alpine:latest  
RUN apk --no-cache add ca-certificates

Then we copy over our compiled binary into the image

COPY --from=builder /go/src/hellofly/hellofly /hellofly

And, importantly, copy over our templates so the binary can find them.

RUN mkdir /templates
COPY --from=builder /go/src/hellofly/templates/hellofly.tmpl /templates

Now we just expose the default port that the hellofly app uses and set the command to run to be hellofly.

EXPOSE 8080
CMD ["/hellofly"]

It's worth remembering this is a fairly standard Dockerfile; there are no Fly specific commands present.

Testing Locally

Running docker build -t hellofly . should create an image locally for testing.

Running docker run -p 8080:8080 -t hellofly will run the hellofly image locally.

You can then connect to http://localhost:8080 where you should see a "Hello from Fly" message.

For the curious: The -p8080:8080 exposes port 8080 locally so you can connect; by default, all ports are closed.

Install Flyctl

We are ready to start working with Fly and that means we need flyctl, our CLI app for managing apps on Fly. If you've already installed it, carry on. If not, hop over to our installation guide

Sign In (or Up) for Fly

If you have a Fly account, all you need to do is sign-in with flyctl.

New User?

Welcome to Fly. To get your Fly account run:

flyctl auth signup

This will take you to the sign-up page where you can either:

  • Sign up with Email: Enter your name, email and password.

  • Sign up with Github: If you have a Github account, you can use that to sign up. Look out for the confirmatory email we will send you which will give you a link to set a password; you'll need a password set so we can actively verify that it is you for some Fly operations.

Returning User

Run:

flyctl auth login

Your browser will open up with the Fly sign-in screen. Enter your user name and password to sign in. If you signed up with Github, use the Sign in with Github button to sign in.

Whichever route you take you will be signed-up, signed-in and returned to your command line, ready to Fly.

Configure the App for Fly

Each Fly application needs a fly.toml file to tell the system how we'd like to deploy it. That file can be automatically generated with the command flyctl init command.

flyctl init
? App Name (leave blank to use an auto-generated name) hellofly
? Select organization: Demo (demo)
? Select builder: Dockerfile
    (Use the existing Dockerfile)
New app created
  Name     = hellofly
  Owner    = demo
  Version  = 0
  Status   =
  Hostname = <empty>

Wrote config file fly.toml

Note: We recommend that you go with the autogenerated names for apps to avoid namespace collisions. We're using hellofly here so you can easily spot it in configuration files.

The fly.toml file now contains a default configuration for deploying your app. In the process of creating that file, flyctl has also created a Fly-side application slot of the same name, "hellofly". If we look at the fly.toml file we can see the name in there:

app = "hellofly"

[[services]]
  internal_port = 8080
  protocol = "tcp"

  [services.concurrency]
    hard_limit = 25
    soft_limit = 20

  [[services.ports]]
    handlers = ["http"]
    port = "80"

  [[services.ports]]
    handlers = ["tls", "http"]
    port = "443"

  [[services.tcp_checks]]
    interval = 10000
    timeout = 2000

The flyctl command will always refer to this file in the current directory if it exists, specifically for the app name value at the start. That name will be used to identify the application to the Fly service. The rest of the file contains settings to be applied to the application when it deploys.

We'll have more details about these properties as we progress, but for now, it's enough to say that they mostly configure which ports the application will be visible on.

Deploying to Fly

We are now ready to deploy our containerized app to the Fly platform. At the command line, just run:

flyctl deploy

This will lookup our fly.toml file, and get the app name hellofly from there. Then flyctl will start the process of deploying our application to the Fly platform. Flyctl will return you to the command line when it's done.

Viewing the Deployed App

Now the application has been deployed, let's find out more about its deployment. The command flyctl info will give you all the essential details.

flyctl info
App
  Name     = hellofly
  Owner    = demo
  Version  = 0
  Status   = running
  Hostname = hellofly.fly.dev

Services
  TASK   PROTOCOL   PORTS
  app    tcp        80 => 8080 [HTTP]
                    443 => 8080 [TLS, HTTP]

IP Addresses
  TYPE   ADDRESS                                CREATED AT
  v4     77.83.140.223                          5m6s ago
  v6     2a09:8280:1:cbda:7e16:7be4:7de4:2a18   5m6s ago
$

As you can see, the application has been deployed on IPv4 and IPv6 and with a DNS hostname of hellofly.fly.dev. Your deployment's name will, of course, be different. Make a note of it and move on to the next section where we will connect to the deployed application.

Connecting to the App

Remembering to replace hellofly.fly.dev with the hostname you got from flyctl info and with your application deployed, open your browser and connect to http://hellofly.fly.dev where you should find a greeting. Use https://hellofly.fly.dev to connect to it securely. Add /to/name and you'll get an extra greeting from the hellofly application.

Hello from Fly Screenshot

You have successfully built, deployed and connected to your first Go application on Fly.