Compare commits
34 Commits
1cbfe28e0e
...
20251118
| Author | SHA1 | Date | |
|---|---|---|---|
|
6d54cbef61
|
|||
|
3062cba541
|
|||
|
f0810eb8e5
|
|||
|
c8684d2d96
|
|||
|
550524cb1a
|
|||
|
4918cef5e6
|
|||
|
bbb21b34dd
|
|||
|
24d66c2fea
|
|||
|
df143c30cc
|
|||
|
9df2de9207
|
|||
|
217779d89a
|
|||
|
18b99e91b3
|
|||
|
6d7d641bc2
|
|||
|
c67fe08a33
|
|||
|
0218c47f2b
|
|||
|
dac497d685
|
|||
|
1e6a3d2596
|
|||
|
a63267ffc2
|
|||
|
b470196abb
|
|||
|
30815a3408
|
|||
|
0fce11557a
|
|||
|
09ffa7afb0
|
|||
|
789c5b434d
|
|||
|
e8bce810a7
|
|||
|
f4c596862f
|
|||
|
cf08d1cb08
|
|||
|
951de2e2b2
|
|||
|
83293947f2
|
|||
|
d73fe8a87a
|
|||
|
899e385b29
|
|||
|
22e5ce5364
|
|||
|
64c491e5c7
|
|||
|
281f21418b
|
|||
|
bb03ef46c6
|
9
Caddyfile
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
default_sni web
|
||||
}
|
||||
|
||||
https:// {
|
||||
tls /tls/tls.crt /tls/tls.key
|
||||
root * /srv
|
||||
file_server
|
||||
}
|
||||
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
# Package versions
|
||||
ARG HUGO_VERSION="0.152.2"
|
||||
ARG CADDY_VERSION="2.10.2"
|
||||
|
||||
# Stage 1: Build
|
||||
FROM core.harbor.brds.ca/d-b.ca/hugo-builder:${HUGO_VERSION} AS builder
|
||||
WORKDIR /project
|
||||
COPY . .
|
||||
RUN hugo --minify build
|
||||
|
||||
# Stage 2: Package
|
||||
FROM docker.io/caddy:${CADDY_VERSION}
|
||||
COPY Caddyfile /etc/caddy/Caddyfile
|
||||
COPY --from=builder /project/public /srv
|
||||
# tls.crt and tls.key should be mounted here at runtime.
|
||||
VOLUME /tls
|
||||
@@ -1,3 +1,3 @@
|
||||
# web
|
||||
# Drew Bowering's Website
|
||||
|
||||
My personal website at https://www.d-b.ca/
|
||||
My personal website at [https://www.d-b.ca/](https://www.d-b.ca/)
|
||||
|
||||
5
archetypes/default.md
Normal file
@@ -0,0 +1,5 @@
|
||||
+++
|
||||
date = '{{ .Date }}'
|
||||
draft = true
|
||||
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||
+++
|
||||
6
archetypes/posts.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
date: '{{ .Date }}'
|
||||
draft: true
|
||||
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||
description: ''
|
||||
---
|
||||
BIN
assets/img/BG_Jasper.jpg
Normal file
|
After Width: | Height: | Size: 3.2 MiB |
BIN
assets/img/DrewBowering.jpg
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/img/d-bca_logo_dark.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
assets/img/d-bca_logo_light.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
69
config/_default/hugo.toml
Normal file
@@ -0,0 +1,69 @@
|
||||
# -- Site Configuration --
|
||||
# Refer to the theme docs for more details about each of these parameters.
|
||||
# https://blowfish.page/docs/getting-started/
|
||||
|
||||
baseURL = "https://d-b.ca/"
|
||||
languageCode = "en"
|
||||
defaultContentLanguage = "en"
|
||||
|
||||
# pluralizeListTitles = "true" # hugo function useful for non-english languages, find out more in https://gohugo.io/getting-started/configuration/#pluralizelisttitles
|
||||
|
||||
enableRobotsTXT = true
|
||||
summaryLength = 0
|
||||
|
||||
buildDrafts = false
|
||||
buildFuture = false
|
||||
|
||||
enableEmoji = true
|
||||
|
||||
# googleAnalytics = "G-XXXXXXXXX"
|
||||
|
||||
[pagination]
|
||||
pagerSize = 100
|
||||
|
||||
[imaging]
|
||||
anchor = 'Center'
|
||||
|
||||
[taxonomies]
|
||||
tag = "tags"
|
||||
category = "categories"
|
||||
author = "authors"
|
||||
series = "series"
|
||||
|
||||
[sitemap]
|
||||
changefreq = 'daily'
|
||||
filename = 'sitemap.xml'
|
||||
priority = 0.5
|
||||
|
||||
[outputs]
|
||||
home = ["HTML", "RSS", "JSON"]
|
||||
|
||||
[related]
|
||||
threshold = 0
|
||||
toLower = false
|
||||
|
||||
[[related.indices]]
|
||||
name = "tags"
|
||||
weight = 100
|
||||
|
||||
[[related.indices]]
|
||||
name = "categories"
|
||||
weight = 100
|
||||
|
||||
[[related.indices]]
|
||||
name = "series"
|
||||
weight = 50
|
||||
|
||||
[[related.indices]]
|
||||
name = "authors"
|
||||
weight = 20
|
||||
|
||||
[[related.indices]]
|
||||
name = "date"
|
||||
weight = 10
|
||||
|
||||
[[related.indices]]
|
||||
applyFilter = false
|
||||
name = 'fragmentrefs'
|
||||
type = 'fragments'
|
||||
weight = 10
|
||||
73
config/_default/languages.en.toml
Normal file
@@ -0,0 +1,73 @@
|
||||
disabled = false
|
||||
languageCode = "en"
|
||||
languageName = "English"
|
||||
weight = 1
|
||||
title = "Drew Bowering"
|
||||
|
||||
[params]
|
||||
displayName = "EN"
|
||||
isoCode = "en"
|
||||
rtl = false
|
||||
dateFormat = "2 January 2006"
|
||||
logo = "img/d-bca_logo_light.png"
|
||||
secondaryLogo = "img/d-bca_logo_dark.png"
|
||||
description = "Drew Bowering's personal website"
|
||||
# copyright = "Copy, _right?_ :thinking_face:"
|
||||
|
||||
[params.author]
|
||||
name = "Drew Bowering"
|
||||
# email = "drew@d-b.ca"
|
||||
image = "img/DrewBowering.jpg"
|
||||
# imageQuality = 96
|
||||
headline = "IT Architect, Developer, Canoeist, Tubist"
|
||||
# bio = "A little bit about me"
|
||||
links = [
|
||||
{ email = "mailto:drew@d-b.ca" },
|
||||
# { link = "https://link-to-some-website.com/" },
|
||||
# { amazon = "https://www.amazon.com/hz/wishlist/ls/wishlist-id" },
|
||||
# { apple = "https://www.apple.com" },
|
||||
# { blogger = "https://username.blogspot.com/" },
|
||||
# { bluesky = "https://bsky.app/profile/username" },
|
||||
# { codepen = "https://codepen.io/username" },
|
||||
# { dev = "https://dev.to/username" },
|
||||
# { discord = "https://discord.gg/invitecode" },
|
||||
# { dribbble = "https://dribbble.com/username" },
|
||||
{ facebook = "https://www.facebook.com/drew.bowering" },
|
||||
# { flickr = "https://www.flickr.com/photos/username/" },
|
||||
# { foursquare = "https://foursquare.com/username" },
|
||||
{ github = "https://github.com/drewbowering" },
|
||||
# { gitlab = "https://gitlab.com/username" },
|
||||
# { google = "https://www.google.com/" },
|
||||
# { hashnode = "https://username.hashnode.dev" },
|
||||
# { instagram = "https://instagram.com/username" },
|
||||
# { itch-io = "https://username.itch.io" },
|
||||
# { keybase = "https://keybase.io/username" },
|
||||
# { kickstarter = "https://www.kickstarter.com/profile/username" },
|
||||
# { lastfm = "https://lastfm.com/user/username" },
|
||||
{ linkedin = "https://www.linkedin.com/in/drew-bowering/" },
|
||||
# { mastodon = "https://mastodon.instance/@username" },
|
||||
# { medium = "https://medium.com/username" },
|
||||
# { microsoft = "https://www.microsoft.com/" },
|
||||
# { orcid = "https://orcid.org/userid" },
|
||||
# { patreon = "https://www.patreon.com/username" },
|
||||
# { pinterest = "https://pinterest.com/username" },
|
||||
# { reddit = "https://reddit.com/user/username" },
|
||||
# { researchgate = "https://www.researchgate.net/profile/username" },
|
||||
# { slack = "https://workspace.url/team/userid" },
|
||||
# { snapchat = "https://snapchat.com/add/username" },
|
||||
# { soundcloud = "https://soundcloud.com/username" },
|
||||
# { spotify = "https://open.spotify.com/user/userid" },
|
||||
# { stack-overflow = "https://stackoverflow.com/users/userid/username" },
|
||||
# { steam = "https://steamcommunity.com/profiles/userid" },
|
||||
# { telegram = "https://t.me/username" },
|
||||
# { threads = "https://www.threads.net/@username" },
|
||||
# { tiktok = "https://tiktok.com/@username" },
|
||||
# { tumblr = "https://username.tumblr.com" },
|
||||
# { twitch = "https://twitch.tv/username" },
|
||||
# { twitter = "https://twitter.com/username" },
|
||||
# { x-twitter = "https://twitter.com/username" },
|
||||
# { whatsapp = "https://wa.me/phone-number" },
|
||||
# { youtube = "https://youtube.com/username" },
|
||||
# { ko-fi = "https://ko-fi.com/username" },
|
||||
# { codeberg = "https://codeberg.org/username"},
|
||||
]
|
||||
13
config/_default/markup.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
# -- Markup --
|
||||
# These settings are required for the theme to function.
|
||||
|
||||
[goldmark]
|
||||
[goldmark.renderer]
|
||||
unsafe = true
|
||||
|
||||
[highlight]
|
||||
noClasses = false
|
||||
|
||||
[tableOfContents]
|
||||
startLevel = 2
|
||||
endLevel = 4
|
||||
69
config/_default/menus.en.toml
Normal file
@@ -0,0 +1,69 @@
|
||||
# -- Main Menu --
|
||||
# The main menu is displayed in the header at the top of the page.
|
||||
# Acceptable parameters are name, pageRef, page, url, title, weight.
|
||||
#
|
||||
# The simplest menu configuration is to provide:
|
||||
# name = The name to be displayed for this menu link
|
||||
# pageRef = The identifier of the page or section to link to
|
||||
#
|
||||
# By default the menu is ordered alphabetically. This can be
|
||||
# overridden by providing a weight value. The menu will then be
|
||||
# ordered by weight from lowest to highest.
|
||||
|
||||
[[main]]
|
||||
name = "Posts"
|
||||
pageRef = "posts"
|
||||
weight = 10
|
||||
|
||||
#[[main]]
|
||||
# name = "Parent"
|
||||
# weight = 20
|
||||
|
||||
#[[main]]
|
||||
# name = "example sub-menu 1"
|
||||
# parent = "Parent"
|
||||
# pageRef = "posts"
|
||||
# weight = 20
|
||||
|
||||
#[[main]]
|
||||
# name = "example sub-menu 2"
|
||||
# parent = "Parent"
|
||||
# pageRef = "posts"
|
||||
# weight = 20
|
||||
|
||||
#[[subnavigation]]
|
||||
# name = "An interesting topic"
|
||||
# pageRef = "tags/interesting-topic"
|
||||
# weight = 10
|
||||
|
||||
#[[subnavigation]]
|
||||
# name = "My Awesome Category"
|
||||
# pre = "github"
|
||||
# pageRef = "categories/awesome"
|
||||
# weight = 20
|
||||
|
||||
#[[main]]
|
||||
# name = "Categories"
|
||||
# pageRef = "categories"
|
||||
# weight = 20
|
||||
|
||||
#[[main]]
|
||||
# name = "Tags"
|
||||
# pageRef = "tags"
|
||||
# weight = 30
|
||||
|
||||
|
||||
# -- Footer Menu --
|
||||
# The footer menu is displayed at the bottom of the page, just before
|
||||
# the copyright notice. Configure as per the main menu above.
|
||||
|
||||
|
||||
# [[footer]]
|
||||
# name = "Tags"
|
||||
# pageRef = "tags"
|
||||
# weight = 10
|
||||
|
||||
# [[footer]]
|
||||
# name = "Categories"
|
||||
# pageRef = "categories"
|
||||
# weight = 20
|
||||
2
config/_default/module.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[[imports]]
|
||||
path = "github.com/nunocoracao/blowfish/v2"
|
||||
167
config/_default/params.toml
Normal file
@@ -0,0 +1,167 @@
|
||||
# -- Theme Options --
|
||||
# These options control how the theme functions and allow you to
|
||||
# customise the display of your website.
|
||||
#
|
||||
# Refer to the theme docs for more details about each of these parameters.
|
||||
# https://blowfish.page/docs/configuration/#theme-parameters
|
||||
|
||||
colorScheme = "blowfish"
|
||||
defaultAppearance = "light" # valid options: light or dark
|
||||
autoSwitchAppearance = true
|
||||
|
||||
enableSearch = true
|
||||
enableCodeCopy = false
|
||||
|
||||
replyByEmail = false
|
||||
|
||||
# mainSections = ["section1", "section2"]
|
||||
# robots = ""
|
||||
|
||||
disableImageOptimization = false
|
||||
disableTextInHeader = false
|
||||
# backgroundImageWidth = 1200
|
||||
|
||||
defaultBackgroundImage = "img/BG_Jasper.jpg" # used as default for background images
|
||||
# defaultFeaturedImage = "IMAGE.jpg" # used as default for featured images in all articles
|
||||
|
||||
highlightCurrentMenuArea = true
|
||||
smartTOC = true
|
||||
smartTOCHideUnfocusedChildren = false
|
||||
|
||||
giteaDefaultServer = "https://git.brds.ca"
|
||||
forgejoDefaultServer = "https://v8.next.forgejo.org"
|
||||
|
||||
[header]
|
||||
layout = "basic" # valid options: basic, fixed, fixed-fill, fixed-gradient, fixed-fill-blur
|
||||
|
||||
[footer]
|
||||
showMenu = true
|
||||
showCopyright = true
|
||||
showThemeAttribution = false
|
||||
showAppearanceSwitcher = true
|
||||
showScrollToTop = true
|
||||
|
||||
[homepage]
|
||||
layout = "background" # valid options: page, profile, hero, card, background, custom
|
||||
#homepageImage = "IMAGE.jpg" # used in: hero, and card
|
||||
showRecent = true
|
||||
showRecentItems = 5
|
||||
showMoreLink = false
|
||||
showMoreLinkDest = "/posts/"
|
||||
cardView = false
|
||||
cardViewScreenWidth = false
|
||||
layoutBackgroundBlur = true # only used when layout equals background
|
||||
|
||||
[article]
|
||||
showDate = true
|
||||
showViews = false
|
||||
showLikes = false
|
||||
showDateOnlyInArticle = false
|
||||
showDateUpdated = false
|
||||
showAuthor = true
|
||||
# showAuthorBottom = false
|
||||
showHero = true
|
||||
heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
||||
layoutBackgroundBlur = true # only used when heroStyle equals background or thumbAndBackground
|
||||
layoutBackgroundHeaderSpace = true # only used when heroStyle equals background
|
||||
showBreadcrumbs = false
|
||||
showDraftLabel = true
|
||||
showEdit = false
|
||||
# editURL = "https://github.com/username/repo/"
|
||||
editAppendPath = true
|
||||
seriesOpened = false
|
||||
showHeadingAnchors = true
|
||||
showPagination = true
|
||||
invertPagination = false
|
||||
showReadingTime = true
|
||||
showTableOfContents = true
|
||||
# showRelatedContent = false
|
||||
# relatedContentLimit = 3
|
||||
showTaxonomies = false
|
||||
showAuthorsBadges = false
|
||||
showWordCount = true
|
||||
# sharingLinks = [ "linkedin", "twitter", "bluesky", "mastodon", "reddit", "pinterest", "facebook", "email", "whatsapp", "telegram"]
|
||||
showZenMode = false
|
||||
|
||||
[list]
|
||||
showHero = true
|
||||
heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
||||
layoutBackgroundBlur = true # only used when heroStyle equals background or thumbAndBackground
|
||||
layoutBackgroundHeaderSpace = true # only used when heroStyle equals background
|
||||
showBreadcrumbs = false
|
||||
showSummary = true
|
||||
showViews = false
|
||||
showLikes = false
|
||||
showTableOfContents = false
|
||||
showCards = false
|
||||
orderByWeight = false
|
||||
groupByYear = true
|
||||
cardView = false
|
||||
cardViewScreenWidth = false
|
||||
constrainItemsWidth = false
|
||||
|
||||
[sitemap]
|
||||
excludedKinds = ["taxonomy", "term"]
|
||||
|
||||
[taxonomy]
|
||||
showTermCount = true
|
||||
showHero = false
|
||||
# heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
||||
showBreadcrumbs = false
|
||||
showViews = false
|
||||
showLikes = false
|
||||
showTableOfContents = false
|
||||
cardView = false
|
||||
|
||||
[term]
|
||||
showHero = false
|
||||
# heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
||||
showBreadcrumbs = false
|
||||
showViews = false
|
||||
showLikes = false
|
||||
showTableOfContents = true
|
||||
groupByYear = false
|
||||
cardView = false
|
||||
cardViewScreenWidth = false
|
||||
|
||||
[firebase]
|
||||
# apiKey = "XXXXXX"
|
||||
# authDomain = "XXXXXX"
|
||||
# projectId = "XXXXXX"
|
||||
# storageBucket = "XXXXXX"
|
||||
# messagingSenderId = "XXXXXX"
|
||||
# appId = "XXXXXX"
|
||||
# measurementId = "XXXXXX"
|
||||
|
||||
[fathomAnalytics]
|
||||
# site = "ABC12345"
|
||||
# domain = "llama.yoursite.com"
|
||||
|
||||
[umamiAnalytics]
|
||||
websiteid = "5ff2ac75-9399-4aae-a0c2-c2799674ebcb"
|
||||
domain = "analytics.brds.ca"
|
||||
# dataDomains = "yoursite.com,yoursite2.com"
|
||||
# scriptName = ""
|
||||
# enableTrackEvent = true
|
||||
|
||||
[selineAnalytics]
|
||||
# token = "XXXXXX"
|
||||
# enableTrackEvent = true
|
||||
|
||||
[buymeacoffee]
|
||||
# identifier = ""
|
||||
# globalWidget = true
|
||||
# globalWidgetMessage = "Hello"
|
||||
# globalWidgetColor = "#FFDD00"
|
||||
# globalWidgetPosition = "Right"
|
||||
|
||||
[verification]
|
||||
# google = ""
|
||||
# bing = ""
|
||||
# pinterest = ""
|
||||
# yandex = ""
|
||||
# fediverse = ""
|
||||
|
||||
[rssnext]
|
||||
# feedId = ""
|
||||
# userId = ""
|
||||
BIN
content/posts/new-website/featured.png
Normal file
|
After Width: | Height: | Size: 1022 KiB |
198
content/posts/new-website/index.md
Normal file
@@ -0,0 +1,198 @@
|
||||
---
|
||||
title: "New Website"
|
||||
date: "2025-06-12T08:00:00-06:00"
|
||||
description: "There's finally a new website at d-b.ca."
|
||||
summary: "I've published my personal website. A brief history of some past endeavours, and some details on the technology behind the new site."
|
||||
---
|
||||
|
||||
I've finally published a proper website at [https://d-b.ca/](https://d-b.ca/).
|
||||
The last time I had anything live on this domain was over 20 years ago,
|
||||
according to the [Wayback Machine](https://web.archive.org/). What took so
|
||||
long? The truth is, my interests have shifted over the years, and I've been
|
||||
learning a lot. This site, while useful in its own right, is really a
|
||||
culmination of a personal platform I've developed over time.
|
||||
|
||||
## History
|
||||
|
||||
My first personal website was developed while I was a student at the
|
||||
[University of Alberta](https://ualberta.ca), near the end of the previous
|
||||
century. The web was still in its early stages, but the university provided
|
||||
students with the means to publish web content. It was mostly a novelty at the
|
||||
time and didn't last beyond my time at school, but it sparked my interest in
|
||||
Internet technologies and their applications.
|
||||
|
||||
That early site included one interesting feature. I developed a mechanism to
|
||||
automatically update a page every time I logged into one of the school's
|
||||
computers, so my friends could find me if they wanted to. At the time,
|
||||
dynamically updating websites was a tricky thing. The most common way was
|
||||
using [CGI](https://en.wikipedia.org/wiki/Common_Gateway_Interface), which is
|
||||
like having a tiny program run every time someone requested a page. The
|
||||
university did not allow student sites to use it. So, I wrote some shell
|
||||
scripts that were called as part of my login and logout scripts that would
|
||||
generate the static HTML file and write it to my web content directory. It
|
||||
needed to handle cases like multiple logins, and the logout script didn't
|
||||
always get triggered, so I'd have to keep an eye on it for stale entries.
|
||||
|
||||
### Self-Hosting
|
||||
|
||||
I've always been an avid self-hoster. Learning by getting a system up and
|
||||
running works well for me. I also value the privacy and control that it
|
||||
provides. Plus, it's much cheaper for me in the long run!
|
||||
|
||||
It really began when I was working at a local Internet service provider. I was
|
||||
able to get a special deal on a good broadband connection at home, which
|
||||
included a small network block (a `/28`, consisting of 16 IP addresses) that I
|
||||
could use. I dedicated my largest machine as my server and developed several
|
||||
services, including a new website.
|
||||
|
||||
My website at that time wasn't fancy, and was geared primarily towards
|
||||
experimentation. I developed a simple content management system from scratch
|
||||
in PHP, which I used to publish a blog. It also integrated with mailing
|
||||
lists, another area I was exploring at the time.
|
||||
|
||||
### D-B.CA
|
||||
|
||||
I hadn't registered a domain name of my own in those early days, so everything
|
||||
resided under a friend's domain. In late 2002, I decided to finally register
|
||||
one of my own, primarily so I could have a stable email address. I wanted to
|
||||
incorporate the initials in my name, so I came up with `d-b.ca`. This was a
|
||||
compromise because someone was squatting on `db.ca` at the time, and, to my
|
||||
knowledge, they still are.
|
||||
|
||||
Early on, I focused mostly on operating my email services and other
|
||||
experiments, with little attention paid to a website. There were a few test
|
||||
pages at times, but nothing substantial.
|
||||
|
||||
## Modern Technology
|
||||
|
||||
One of the projects I've been following is [Hugo](https://gohugo.io/). I've
|
||||
seen and worked with various web content management systems in the past, and
|
||||
they often feel cumbersome and present security concerns. Hugo is an example
|
||||
of a "Static Site Generator." Think of it like this: instead of creating web
|
||||
pages on the fly every time someone visits, Hugo takes all the raw content and
|
||||
turns it into a set of ready-to-serve files, much like a compiler turns code
|
||||
into an executable program. The resulting static resources can be served as
|
||||
regular files from any web service, without the need for dynamically
|
||||
generating content upon request from a database, as traditional CMS systems
|
||||
do.
|
||||
|
||||
Using Hugo is much easier with a solid base template. There are
|
||||
[many to choose from](https://themes.gohugo.io/), including the one I've
|
||||
selected here called ["Blowfish"](https://blowfish.page/). I like how it
|
||||
looks, and it supports the style of site that this is very well.
|
||||
|
||||
Another benefit of a static site generator is that all the sources for the
|
||||
site can be treated like software code, making it simple to use development
|
||||
tools like [Git](https://git-scm.com/) for version control. I keep the sources
|
||||
for this site in a public repository on my own Git server. Feel free to take a
|
||||
look:
|
||||
|
||||
{{< gitea repo="d-b.ca/web" >}}
|
||||
|
||||
### CI/CD
|
||||
|
||||
I've also set up a CI/CD pipeline to build and deploy the site whenever
|
||||
changes are made to the source repository. What does this mean?
|
||||
|
||||
**CI** = *Continuous Integration*
|
||||
> This is the practice of frequently integrating changes into a source
|
||||
> repository. The changes are checked, assembled, and packaged through
|
||||
> automated processes. [More information](https://martinfowler.com/articles/continuousIntegration.html)
|
||||
|
||||
**CD** = *Continuous Delivery*
|
||||
> This is the capability of being able to take new changes (such as the
|
||||
> outputs of the CI process) and getting them deployed and running
|
||||
> automatically. [More information](https://continuousdelivery.com/)
|
||||
|
||||
The CI portion is triggered by a push to the
|
||||
[`web`](https://git.brds.ca/d-b.ca/web) repository. It runs an automated
|
||||
workflow that builds the site and packages the resulting artifacts into a
|
||||
container image based on the [Caddy](https://caddyserver.com/) web server.
|
||||
|
||||
A container image is like a pre-packaged software environment that ensures the
|
||||
website runs consistently regardless of the underlying infrastructure. The
|
||||
resulting image contains everything the website needs to operate and can run
|
||||
on any infrastructure that can support it, such as my own laptop or my server
|
||||
cluster.
|
||||
|
||||
The build container with Hugo is another image that is only used to create the
|
||||
website container. I maintain it in this repository:
|
||||
|
||||
{{< gitea repo="d-b.ca/hugo-builder" >}}
|
||||
|
||||
After the workflow has built the container image for running the website, it
|
||||
updates the CD GitOps repository to deploy this new version immediately to a
|
||||
private staging site. Another definition:
|
||||
|
||||
> **GitOps** refers to the practice of managing infrastructure automation by
|
||||
> keeping machine-readable descriptions of the intended infrastructure in a
|
||||
> version-controlled Git repository. A CD system will monitor the repository
|
||||
> for changes, immediately adding, modifying, or removing infrastructure to
|
||||
> bring the state of the operational system into alignment with the source
|
||||
> description.
|
||||
|
||||
There are many benefits to managing infrastructure this way. Changes are
|
||||
automatically tracked because everything is stored in an existing code
|
||||
repository system that's specifically designed for managing and tracking
|
||||
change. Problematic changes can be reverted easily by reverting the change in
|
||||
the repository. Automation keeps things in sync at all times - any changes
|
||||
made manually outside of this system are immediately spotted and removed.
|
||||
|
||||
When I want to publish the new version as the production website, I use my
|
||||
regular private production GitOps repository to update the image version tag,
|
||||
and the rest happens automatically. The CD repository for the staging site is
|
||||
public, you're welcome to check it out here:
|
||||
|
||||
{{< gitea repo="d-b.ca/db-cd" >}}
|
||||
|
||||
#### Pipeline Diagram
|
||||
|
||||
{{< mermaid >}}
|
||||
flowchart TB
|
||||
subgraph GIT [Git Repository]
|
||||
WR[(Web)]
|
||||
CDR[(CD)]
|
||||
end
|
||||
|
||||
WP(Push Web Updates)-->WR
|
||||
WP ~~~ HBI
|
||||
|
||||
subgraph CI [CI Workflow]
|
||||
CIP[Pull Source
|
||||
Repository]-->BWI[Build Web
|
||||
Image]
|
||||
BWI-->PWI[Push Web
|
||||
Image]
|
||||
PWI-->UCD[Update CD
|
||||
Repository]
|
||||
end
|
||||
|
||||
PWI-->WI
|
||||
WR-->CIP
|
||||
|
||||
subgraph DOCKER [Image Repository]
|
||||
HBI((Hugo
|
||||
Build))
|
||||
WI((Web))
|
||||
end
|
||||
|
||||
HBI-->BWI
|
||||
|
||||
UCD-->CDP(Push Image
|
||||
Update)
|
||||
CDP-->CDR
|
||||
CDR-->CDPull
|
||||
|
||||
subgraph CD [CD Process]
|
||||
CDPull[Pull Source Repository]-->DWI[Deploy Web Image]
|
||||
end
|
||||
|
||||
WI-->DWI
|
||||
{{< /mermaid >}}
|
||||
|
||||
## Underlying Platform
|
||||
|
||||
In future articles, I'll describe the evolution of the physical network and
|
||||
systems this site is running on, and how they enabled me to build a
|
||||
[Kubernetes](https://kubernetes.io/) cluster to scale this site and run other
|
||||
services, all on hardware I assembled myself!
|
||||
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module git.brds.ca/drew/web
|
||||
|
||||
go 1.25.4
|
||||
|
||||
require github.com/nunocoracao/blowfish/v2 v2.92.0 // indirect
|
||||
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/nunocoracao/blowfish/v2 v2.92.0 h1:1EgHMRaY6VI438TIAN/5luNx16lg1e0Lrbi+6kDxpdA=
|
||||
github.com/nunocoracao/blowfish/v2 v2.92.0/go.mod h1:4SkMc+Ht8gpQCwArqiHMBDP3soxi2OWuAhVney+cuyk=
|
||||
BIN
static/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
static/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
static/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
static/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 592 B |
BIN
static/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
static/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
1
static/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||