Gatsby Blog with a MeiLi Search Backend
I already looked into how to:
- Deploy a MeiLi Search Engine with Docker
- Build a Search Interface with React.js
- Use Gatsby.js to pre-render the React.js Interface
The next step is to wrap the pre-rendered build inside a Docker container that uses goFiber to serve the generated static HTML/CSS/JS/JSON code.
Prepare the goFiber Webserver
The code for the webserver is fairly simple - very similar to Express.js:
package main
import (
"flag"
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
)
var (
port = flag.String("port", ":8888", "Port to listen on")
prod = flag.Bool("prod", false, "Enable prefork in Production")
)
func main() {
// Create fiber app
// Development
// app := fiber.New(fiber.Config{
// Prefork: *prod, // go run app.go -prod
// })
// Production
app := fiber.New(fiber.Config{
Prefork: true,
})
// Middleware
app.Use(recover.New())
app.Use(logger.New())
// Setup static files
app.Static("/", "./data/public")
// Listen on port 8888
log.Fatal(app.Listen(*port)) // go run app.go -port=:8888
}
The webserver expects our static code - generated from our React.js MeiLi search interface and pre-rendered by Gatsby.js - in the public
folder. It will then serve it on /
with port 8888
.
Building the Go App
We can now use Docker to build the webserver inside a Golang Container and then transfer our website code and the build binary into a tiny Alpine Container:
# Building the binary of the App
FROM golang:alpine AS build
# Project labels
LABEL maintainer="m.polinowski@gmail.com"
# `build` can be replaced with your project name
WORKDIR /go/src/build
# Copy all the Code and stuff to compile everything
COPY ./container/* ./
# Downloads all the dependencies in advance (could be left out, but it's more clear this way)
RUN go mod download
# Builds the application as a staticly linked one, to allow it to run on alpine
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o app .
# Moving the binary to the 'final Image' to make it smaller
FROM alpine:latest
WORKDIR /app
# Create the `public` dir and copy all the assets into it
RUN mkdir ./data
COPY ./container/data ./data
# `build` can be replaced here as well
COPY --from=build /go/src/build/app .
# Exposes port 8888 because our program listens on that port
EXPOSE 8888
# CMD ["./app"]
RUN chmod +x ./data/run.sh
CMD ["ash", "./data/run.sh"]
CI Pipeline
Now I would use a Gitlab CI pipeline to do my Gatsby.js build as well as the build described above. But this also works locally with a npm script that we can add to the package.json file of our Gatsby.js app:
"scripts": {
"build": "node --max-old-space-size=8192 node_modules/gatsby/dist/bin/gatsby build",
"develop": "node --max-old-space-size=8192 node_modules/gatsby/dist/bin/gatsby develop",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"docker": "mv public/* docker/container/data/public && docker build -t my_blog docker/. && mv docker/container/data/public/* public"
}
So now we can enter the root dir of our Gatsby.js app and execute:
npm run build
npm run docker
Now we have both container images ready to be served:
REPOSITORY TAG SIZE
my_blog latest 23.4MB
getmeili/meilisearch latest 258MB
Docker Compose
Now we can write a docker-compose.yml
that brings it all together for us - Note that I ran into an issue here. I am building the Gatsby.js page while starting the MeiLi Search container manually (without Compose). I am connecting to the service on localhost
. If I now use a virtual network for those container I will have to change the connection URL from localhost:7700
to meilisearch:7700
. But to keep this simple I just run the container on the host
network stack here - so nothing needs to be changed:
version: '3'
services:
meilisearch:
container_name: meilisearch
image: getmeili/meilisearch:latest
environment:
- MEILI_MASTER_KEY=RhTX1pLPSKSn7KW9yf9u_MNKC0v1YKkmx2Sc6qSwbLQ
- MEILI_NO_ANALYTICS=true
# - MEILI_ENV=development
- MEILI_ENV=production
network_mode: "host"
# ports:
# - ${MEILI_PORT:-7700}:7700
# networks:
# - meilisearch
volumes:
- /opt/meili_data:/meili_data
restart: unless-stopped
gatsby_frontend:
container_name: my_blog
image: my_blog:latest
network_mode: "host"
# ports:
# - 8888:8888
# networks:
# - meilisearch
restart: unless-stopped
# networks:
# meilisearch:
# driver: bridge
You can now bring the application up with:
docker-compose up
and visit http://localhost:8888
and should see the Gatsby.js frontend being served by your goFiber webserver connecting to your MeiLi Search backend:
👍