Hosting static site with App Engine, Cloud Build and Hugo

So once in a while I try new platform to host my blog. So far i’ve tried Heroku+Jekyll, VPS+Nginx, Netlify+Hugo.

Every option has its Cons and Pros but this post is about: App Engine + Cloud Build + Hugo.

Requirements

Note: if you’re looking for the simplest setup it’s the Netlify, IMO.

App Engine + Cloud Build

satisfies the requirements above:

There are some cons as well:

Prerequisites

  1. create a GCP project or use an existing one.
  2. configure domain and TLS. Google’s managed domains are auto provisioned with Free TLS certificates.
  3. set the daily spend quotas, just to be safe…
  4. configure IAM permissions so Cloud Build is capable deploying App Engine apps: find project_number@cloudbuild.gserviceaccount.com and add “App Engine Admin”, “App Engine Deployer” roles.
  5. configure App Engine for the static app see App.yaml below
  6. create a build trigger for a connected source repository
  7. edit the build trigger and specify the path to the cloudbuild.yaml in your source repository. In my case it’s deploy/cloudbuild.yaml
  8. configure site comilation step; see the cloudbuild.yaml below
  9. configure App Engine deployment step; see the cloudbuild.yaml below

Deployment

  1. git push origin
  2. ???
  3. Profit!!!

References

app.yaml

A runtime suitable for static content.

runtime: python27
api_version: 1
threadsafe: true
instance_class: F1
# disable automatic scaling to avoid incurring costs
automatic_scaling:
  target_cpu_utilization: 0.65
  min_instances: 0
  max_instances: 1
  min_pending_latency: 30ms  # default value
  max_pending_latency: automatic
  max_concurrent_requests: 50

# See the reference for more details
# https://cloud.google.com/appengine/docs/standard/python/config/appref
handlers:

## static content routing
- url: /
  static_files: public/index.html
  upload: public/*

# hugo generates pages in directories so check for index.html first
- url: /(.*)/
  static_files: public/\1/index.html
  upload: public/*

- url: /
  static_dir: public/

error_handlers:
  - file: default_error.html

cloudbuild.yaml

Build steps using Hugo to compile the site.

substitutions:
  _HUGO_VERSION: "0.52"

images: 
  - 'gcr.io/$PROJECT_ID/hugo-${_HUGO_VERSION}:latest'
  
# https://cloud.google.com/cloud-build/docs/build-config
steps:
# the step needed only only when creating/updating Hugo image
- id: 'budil hugo img'
  name: 'gcr.io/cloud-builders/docker'
  args: [
            'build',
            '--build-arg', 'HUGO_VERSION=${_HUGO_VERSION}',
            '-t', 'gcr.io/$PROJECT_ID/hugo-${_HUGO_VERSION}:latest',
            '--cache-from', 'gcr.io/$PROJECT_ID/hugo-${_HUGO_VERSION}:latest',
            '-f', 'deploy/hugo.Dockerfile', 'deploy/'
        ]

- id: 'hugo build site'
  name: 'gcr.io/$PROJECT_ID/hugo-${_HUGO_VERSION}:latest'
  entrypoint: 'sh'
  args:
    - -c
    - |
      hugo -s ./src
      mv public/ deploy/

- id: 'gcloud deploy app'
  name: gcr.io/cloud-builders/gcloud-slim
  dir: deploy/
  args: ['--project=$PROJECT_ID', 'app', 'deploy', 'app.yaml']

options:
  machineType: 'N1_HIGHCPU_32'

timeout: '120s'
  

hugo.Dockerfile

Required to build hugo docker image.

FROM alpine:3.5 as build

ARG HUGO_VERSION=0.52
ENV HUGO_BINARY=hugo_${HUGO_VERSION}_Linux-64bit.tar.gz

# Install Hugo
RUN set -x && \
  apk add --update wget ca-certificates && \
  wget -q https://github.com/spf13/hugo/releases/download/v${HUGO_VERSION}/${HUGO_BINARY} && \
  tar xzf ${HUGO_BINARY} && \
  rm -r ${HUGO_BINARY} && \
  mv hugo /usr/bin && \
  apk del wget ca-certificates && \
  rm /var/cache/apk/*

ENTRYPOINT ["/usr/bin/hugo"]

GCP Free Quotas