I use Docker
to run several microservices across my websites. Generally, they are standalone tools
and demonstrations, mostly made to teach myself how to get these things done in microservices.
I recently came across the concept of utility containers. Up to now, all the containers I run are meant to run all the time, and be easily replaced by spinning up a replacement container. Utility containers, on the other hand, are literally containers that hold the bits needed to process input data into output data, do that process, then exit.
At the same time, I’ve been transitioning from Google’s blogger platform onto my in-home hardware,
using Hugo. I’ve written my own little Docker utility container to hold
the go
language and the Hugo
executable, specifically made to process data checked out from
my hugo-content
and hugo-static
(private) repositories and automatically check the outputs back
into my blog-htdocs repository.
I’m writing this post directly on my gitlab website, and it will be the first post that I’m writing
directly into source control, to be processed by my hugo-builder
container, and posted publicly.
Detail: Dockerfile
NOTE: As this is a test-post, the below is VERY likely to change (possibly, in many ways).
# Docker 20.10.16
FROM alpine:latest
MAINTAINER Gary Allen Vollink g.hugo@vollink.com
RUN apk update \
&& apk upgrade \
&& apk add coreutils shadow bash openssh curl go git \
&& mkdir /root/.ssh \
&& ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 \
-N '' -C 'git@hugobuilder' -q \
&& chmod 700 /root/.ssh \
&& chmod 600 /root/.ssh/id_ed25519 \
&& chmod 644 /root/.ssh/id_ed25519.pub \
&& curl -LOs https://github.com/gohugoio/hugo/releases/download/v0.99.1/hugo_0.99.1_Linux-64bit.tar.gz \
&& cd /usr/local/bin \
&& tar xfz /hugo_0.99.1_Linux-64bit.tar.gz \
&& rm LICENSE README.md \
&& /bin/echo "#######################" \
&& /bin/echo "## Add key to gitlab." \
&& /bin/echo "#######################" \
&& cat /root/.ssh/id_ed25519.pub \
&& /bin/echo "#######################"
COPY src/* /run/
CMD /run/entry.sh
Detail: entry.sh
For now, I’m not sharing the whole thing. Key points:
- Does
/work
exist (it came from-v
on the command line):- Store the owner’s UID
SAVED_USERID
- Store the owner’s GID
SAVID_GROUPID
- Store the owner’s UID
- If There’s no user for SAVED_USERID
- Create the user (and group if needed)
- If there is a user for SAVED_USERID
- Modify the user to make sure it can be used for work
- Get or add a home directory
- Make sure the shell is set to bash
- If /work doesn’t exist, use UID/GID 33 (Ubuntu’s www-data userid)
- Create
/work
- Create
- Back up any .ssh and .gitconfig that are “in the way”
- Copy the /root/.ssh to the user folder.
- Execute the
go_hugo.sh
script (see below). - Cleanup/revert any .ssh changes
- Cleanup/revert any .gitconfig changes
Details go_hugo.sh
#!/bin/bash
#############################################################################
VAR_ERROR=""
cd /work
# Read the environment package that entry.sh left us.
if [ -r "$1" ]
then
echo "Reading $1"
eval $(cat "$1")
else
echo "Unable to read $1"
ls -ld "$1"
fi
# Read any environment package that a user put in /work
if [ -r "/work/hugobuilder.env" ]
then
eval $(cat "/work/hugobuilder.env")
fi
# Check for expected variables
# These should all have something, even if left unused.
if [ -z "$GROUP_NAME" ]
then
VAR_ERROR="${VAR_ERROR}GROUP_NAME:"
fi
if [ -z "$WORK_GID" ]
then
VAR_ERROR="${VAR_ERROR}WORK_GID:"
fi
if [ -z "$WORK_NAME" ]
then
VAR_ERROR="${VAR_ERROR}WORK_NAME:"
fi
if [ -z "$WORK_HOME" ]
then
VAR_ERROR="${VAR_ERROR}WORK_HOME:"
fi
if [ -z "$WORK_UID" ]
then
VAR_ERROR="${VAR_ERROR}WORK_UID:"
fi
if [ -z "$HAS_CONFIG" ]
then
VAR_ERROR="${VAR_ERROR}HAS_CONFIG:"
fi
if [ ! -z "$VAR_ERROR" ]
then
echo "ERR: Expected variables missing: ${VAR_ERROR}"
echo "HAS_CONFIG=$HAS_CONFIG"
exit 2
fi
if [ -z "$GIT_SSH_COMMAND" ]
then
# ONLY if the user has not given us a better one.
GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null"
GIT_SSH_COMMAND="${GIT_SSH_COMMAND} -o StrictHostKeyChecking=no"
fi
export GIT_SSH_COMMAND
if [ -r "/work/.gitconfig" ]
then
# If it exists, this was already backed up by entry.sh
cp "/work/.gitconfig" "${WORK_HOME}/.gitconfig"
fi
# See if we have the two settings needed for `git commit`
# Assume we don't
_NEED_GCFG_E=1
_NEED_GCFG_N=1
if [ -r "${WORK_HOME}/.gitconfig" ]
then
grep 'user.email' "${WORK_HOME}/.gitconfig" 2>&1 >/dev/null
if [ "0" = "$?" ]
then
# Unless we find it
_NEED_GCFG_E=0
fi
grep 'user.name' "${WORK_HOME}/.gitconfig" 2>&1 >/dev/null
if [ "0" = "$?" ]
then
_NEED_GCFG_N=0
fi
fi
# Add needed git settings.
if [ "1" = "${_NEED_GCFG_E}" ]
then
git config --global user.email "hugobuilder-auto@vollink.com"
fi
if [ "1" = "${_NEED_GCFG_N}" ]
then
git config --global user.name "Hugo Builder Automation"
fi
if [ ! -d "/work/blog/.git" ]
then
git clone --recursive \
ssh://git@gitlab.home.vollink.com:30022/external/blog-htdocs.git \
"/work/blog"
if [ "0" -ne "$?" ]
then
echo "ERROR: git failed."
echo "Was key added to gitlab?"
echo "===>"
cat ${WORK_HOME}/.ssh/id_ed25519.pub
echo "<==="
exit 1
fi
if [ ! -d "/work/blog/htdocs" ]
then
echo "ERROR: git claims success, but blog/htdocs was not created."
exit 1
fi
fi
cd /work
if [ ! -d "/work/hugo-blog/.git" ]
then
git clone --recursive \
ssh://git@gitlab.home.vollink.com:30022/home/web/hugo-blog.git \
"/work/hugo-blog"
if [ "0" -ne "$?" ]
then
echo "ERROR: git failed."
echo "Was key added to gitlab?"
echo "===>"
cat ${WORK_HOME}/.ssh/id_ed25519.pub
echo "<==="
exit 1
fi
if [ ! -d "/work/hugo-blog" ]
then
echo "ERROR: git claims success, but hugo-blog/ was not created."
exit 1
fi
fi
cd /work/hugo-blog
git fetch --all
git pull
git submodule foreach git pull origin master
##
# before running hugo: do I have a config?
if [ -r "${HAS_CONFIG}" ]
then
cp "${HAS_CONFIG}" "/work/hugo-blog/."
fi
/usr/local/bin/hugo --destination "/work/blog/htdocs"
# This is bullshit, by the way... if there is a git FOLDER in the
# destination, hugo will delete it entirely before replacing everything,
# so I've set this up so the destination is one layer deep.
rm /work/blog/htdocs/.git
cd /work/blog
git add .
if [ "0" = "$?" ]
then
git commit -m 'docker hugobuilder automated check-in.'
if [ "0" = "$?" ]
then
git push origin master
if [ "0" -ne "$?" ]
then
exit 1
fi
fi
fi
Update
The page above was run through the hugobuilder
container and deployed using a git pull
from my web server.
With this edit, I’m going to attempt to let the hugobuilder
and my various crontabs deploy this automatically
(checks are done on a 10 minute schedule). There won’t need to be a further update if this just works.