Github Pages Alpine
Overview
Following on from an init blog post where I got up and running with the Github Pages Gem using a local Docker environment, I found I wanted to start blogging from my 12" macbook. The macbook has a 500GB SSD and with the Starefossen docker-github-pages Dockerfile building to an image over 845MB in size, I decided to author a new Dockerfile, minimising the image size as much as I could.
Creating the Dockerfile
The Starefossen Dockerfile I used previously is descended from Debian Jessie which has an uncompressed image size of 51.4 MB. I decided to try using Alpine Linux as a base, weighing in at only 5MB. Keen to avoid reinventing the wheel if possible, I found madducci docker-github-pages, pulled it down and tried it out. Whilst the madduci alpine-github-pages Dockerfile proved functionally sufficient, the built image weighed in at 186.4MB uncompressed. I decided to use it as a reference and see if there were any optimisations I could add.
Firstly I added an environment variable declaring the version of the Github Pages Gem I want to use. Reviewing the list of Github Pages dependencies and versions I noticed that the Starefossen image I was using previously runs an out of date version of the Github Pages gem.
ENV GITHUB_GEM_VERSION 111
I then moved all dependencies required to build the Github Pages Ruby Gem into an environment variable, to facilitate easier reading and tidier apk add and apk del statements. Apk provides a namespacing option that allows to install packages under a namespace. This namespace mechanism also allows for all packages in a namespace to be removed with just the namespace as an argument, e.g:
apk add --virtual .build-deps gcc g++ make ...
apk del .build-deps
On this occasion the environment variable approach looked quicker and easier to read to me.
ENV BUILD_DEPS \
gcc \
g++ \
make \
curl \
bison \
ca-certificates \
tzdata \
ruby-dev \
glib-dev \
libc-dev \
ruby-bundler \
ruby-irb
Wrapping the commands necessary to install the Github Pages Gem (which pulls in Jekyll as a dependency) in a single RUN instruction limits the number of layers in the final image and so aids in minimising image size.
RUN apk add --no-cache $BUILD_DEPS ruby && \
echo 'gem: --no-document' > /etc/gemrc && \
gem install github-pages:${GITHUB_GEM_VERSION} && \
apk del $BUILD_DEPS && \
rm -rf /usr/lib/ruby/gems/2.3.0/cache && \
mkdir -p /usr/src/app
Apk includes a new –no-cache option as of Aline Linux 3.3. The –no-cache option removes the need to run an apk update and remove any apk cache files. Gem cache files are removed as I do not expect to want to use Gem in the container after the image is built.
Finally I decided on running Jekyll as I would ordinarily as a convenience. The Docker CMD reference states “The main purpose of a CMD is to provide defaults for an executing container” so this seemed appropriate.
CMD jekyll serve -d /_site --incremental -H 0.0.0.0 -P 4000
The Result
richardjennings/github-pages-alpine at 21MB compressed and 57.99MB uncompressed. That seems a little more reasonable.