Posted by James Ward, Developer Advocate
Recently I completed the migration of my blog from Wordpress to Hugo and I wanted to take advantage of it now being a static site by hosting it on a Content Delivery Network (CDN). With Hugo the source content is plain files instead of rows in a database. In the case of my blog those files are in git on GitHub. But when the source files change, the site needs to be regenerated and redeployed to the CDN. Also, sometimes it is nice to have drafts available for review. I setup a continuous delivery pipeline which deploys changes to my prod site on Firebase Hosting and drafts on Cloud Run, using Cloud Build. Read on for instructions for how to set all this up.
If you have an existing Hugo project you'll need to add some files to it:
.firebaserc
{ "projects": { "production": "hello-hugo" } }
cloudbuild-draft.yaml
steps: - name: 'gcr.io/cloud-builders/git' entrypoint: '/bin/sh' args: - '-c' - | # Get the theme git submodule THEME_URL=$(git config -f .gitmodules --get-regexp '^submodule\..*\.url$' | awk '{ print $2 }') THEME_DIR=$(git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | awk '{ print $2 }') rm -rf themes git clone $$THEME_URL $$THEME_DIR - name: 'gcr.io/cloud-builders/docker' entrypoint: '/bin/sh' args: - '-c' - | docker build -t gcr.io/$PROJECT_ID/$REPO_NAME-$BRANCH_NAME:$COMMIT_SHA -f - . << EOF FROM klakegg/hugo:latest WORKDIR /workspace COPY . /workspace ENTRYPOINT hugo -D -p \$$PORT --bind \$$HUGO_BIND --renderToDisk --disableLiveReload --watch=false serve EOF docker push gcr.io/$PROJECT_ID/$REPO_NAME-$BRANCH_NAME:$COMMIT_SHA - name: 'gcr.io/cloud-builders/gcloud' args: - run - deploy - --image=gcr.io/$PROJECT_ID/$REPO_NAME-$BRANCH_NAME:$COMMIT_SHA - --platform=managed - --project=$PROJECT_ID - --region=us-central1 - --memory=512Mi - --allow-unauthenticated - $REPO_NAME-$BRANCH_NAME
cloudbuild.yaml
steps: - name: 'gcr.io/cloud-builders/git' entrypoint: '/bin/sh' args: - '-c' - | # Get the theme git submodule THEME_URL=$(git config -f .gitmodules --get-regexp '^submodule\..*\.url$' | awk '{ print $2 }') THEME_DIR=$(git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | awk '{ print $2 }') rm -rf themes git clone $$THEME_URL $$THEME_DIR - name: 'gcr.io/cloud-builders/curl' entrypoint: '/bin/sh' args: - '-c' - | curl -sL https://github.com/gohugoio/hugo/releases/download/v0.69.2/hugo_0.69.2_Linux-64bit.tar.gz | tar -zxv ./hugo - name: 'gcr.io/cloud-builders/wget' entrypoint: '/bin/sh' args: - '-c' - | # Get firebase CLI wget -O firebase https://firebase.tools/bin/linux/latest chmod +x firebase # Deploy site ./firebase deploy --project=$PROJECT_ID --only=hosting
firebase.json
{ "hosting": { "public": "public" } }
^master$
branch:
Create a new trigger:
Give it a name like drafts-trigger
, specify the branch selector as
.*
(i.e. any branch), and the build configuration file type to "Cloud
Build configuration file" with a value of cloudbuild-draft.yaml
Setup permissions for the Cloud Build process to manage Cloud Run and Firebase Hosting by
visiting the IAM management page, locate the member with the name ending with
@cloudbuild.gserviceaccount.com
, and select the "pencil" / edit
button:
Add a role for "Cloud Run Admin" and another for "Firebase Hosting Admin":
Your default "prod" trigger isn't read to test yet, but you can test the drafts on Cloud Run
by going back to the
Cloud Build Triggers page, and clicking the "Run Trigger" button on the
"drafts-trigger" line. Check the build logs by finding the build in the Cloud Build History.
Once the build completes visit the Cloud
Run console to find your newly created service which hosts the drafts version of
your new blog. Note that the service name includes the branch so that you can see drafts from
different branches.
Now you'll need your project id, which can be found in the URL on the Firebase Project Overview page. The URL for my project is:
console.firebase.google.com/project/jw-demo/overview
Which means my project id is: jw-demo
Now copy your project id go into your GitHub fork, select the
.firebaserc
file and click the "pencil" / edit button:
Replace the hello-hugo
string with your project id and commit the
changes. This commit will trigger two new builds, one for the production site and one for the
drafts site on Cloud Run. You can check the status of those builds on the Cloud Build History
page. Once the default trigger (the one for Firebase hosting) finishes, check out
your Hugo site running on Firebase Hosting by navigating to (replacing YOUR_PROJECT_ID with
the project id you used above): https://YOUR_PROJECT_ID.web.app/
Your prod and drafts sites are now automatically deploying on new commits!
There are many themes for Hugo and they
are easy to change. Typically themes are pulled into Hugo sites using git submodules. To
change the theme, edit your .gitmodules
file and set the
subdirectories and url. As an example, here is the content when using the mainroad theme:
[submodule "themes/mainroad"] path = themes/mainroad url = https://github.com/vimux/mainroad.git
You will also need to change the theme
value in your
config.toml
file to match the directory name in the
themes
directory. For example:
theme = "mainroad"
Note: At the time of writing this, Cloud Build does not clone git submodules so the
cloudbuild.yaml
does the
cloning instead.
To setup local editing you will first need to clone your fork. You can do this with the GitHub desktop app. Or from the command line:
git clone --recurse-submodules https://github.com/USER/REPO.git
Once you have the files locally, install Hugo, and from inside the repo's directory, run:
hugo -D serve
This will serve the drafts in the site. You can check out the site at: localhost:1313
Committing non-draft changes to master and pushing those changes to GitHub will kick off the build which will deploy them on your prod site. Committing draft to any branch will kick off the build which will deploy them on a Cloud Run site.
Hopefully that all helps you with hosting your Hugo sites! Let me know if you run into any problems.