Heroku: Docker, Go, React

December 29 2019
Archived

We're going to deploy a React Application to Heroku that will be served from a Go backend which is then neatly wrapped in a Docker image.

You'll need the following:

  • Golang (I am using v1.13.5)
  • npm
  • A text editor (VSCode is what I am using)
  • A unix based terminal
  • Docker
  • A Heroku account and the Heroku CLI

What is Heroku?

From their page

"Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud."

Use CRA to set up a React app

We're going to use create-react-app to bootstrap our React project.

npx create-react-app deployment-demo

Write the Go backend to serve it

Let's change directory into our newly created react project, create a sub-directory called server and create a file called server.go in it:

cd deployment-demo/ && mkdir "server" && cd "$_" && touch server.go

Open up your favourite text editor and paste the following into server.go:

package main

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

func main() {
    /*
        Grab the environment variable that has been hopefully set, but also set up a default
    */
    port := os.Getenv("PORT")
    defaultPort := "8080"
    /*
        Serve the contents of the build directory that was produced as a part of `npm run build` on the root `/`
    */
    http.Handle("/", http.FileServer(http.Dir("./build")))

    /*
        Check if the port environment variable has been set and if so, use that, otherwise let's use a reasonable default
    */
    if !(port == "") {
        log.Fatal(http.ListenAndServe(":"+port, nil))
    } else {
        log.Fatal(http.ListenAndServe(":"+defaultPort, nil))
    }
}

Caveat: Heroku gives us a port to bind our web application to, so we grab that from an environment variable, you can read more about it here

Build a production version of our application

From our current directory ../deployment-demo/server go up a level back to the root of our React project, and run:

npm run build

This will produce a directory called build.

Let's copy this into our server directory, which will serve as our production payload.

cp -r build/ server/

We can now navigate back into our server directory and start deploying.

Docker

Create the following Dockerfile in the server directory:

# Stage 1
FROM golang:alpine as builder
RUN apk update && apk add --no-cache git
RUN mkdir /build 
ADD . /build/
WORKDIR /build
RUN go get -d -v
RUN go build -o deployment-demo .
# Stage 2
FROM alpine
RUN adduser -S -D -H -h /app appuser
USER appuser
COPY --from=builder /build/ /app/
WORKDIR /app
CMD ["./deployment-demo"]

Heroku

Create an app

If you don't have a Heroku account, go and create one! (it should take less than 5 minutes)

Once that's done, you're going to need the Heroku CLI, which can be easily installed on Ubuntu by running:

sudo snap install heroku --classic

After installing the CLI, run the following command to login:

heroku login

This will open a browser window for you to login (it's an extremely cool system)

Now run:

heroku create [YOUR_APP_NAME]

in the deployment-demo/server/ directory.

An app will be created for you on your Heroku account and you should be able to see it on your dashboard

The Container Registry

The Heroku Container Registry allows you to deploy Docker images to Heroku.

You can read more about it here.

Run the following to login in to the registry:

heroku container:login

Run this command to build your Docker image and push it to Heroku:

heroku container:push web --app [YOUR_APP_NAME]

Notice that we specify web, this indicates the process type we want to associate with this application. Further reading on process types can be found here.

And finally, run this to release the image to your application:

heroku container:release web --app [YOUR_APP_NAME]

We should now be able to navigate to our application hosted on Heroku by running:

heroku open --app [YOUR_APP_NAME]

And we should see the following:

https://res.cloudinary.com/practicaldev/image/fetch/s--zbQAc3sz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0rfhrd634snglvyavvgj.png

That's it! That's all you need to do to deploy a Docker image running a Go server that serves a React application to Heroku!