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:
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!