Build OCI images with Buildah on sourcehut
Post created: 2020-03-29
Post updated: 2020-05-15
Written by Marcel Mehlmann
I like the concept of containerization. Isolating1 applications and deploying them with only a few commands on a large fleet of servers surely has its benefits. One major and importen part of every container setup is automation. If you are running arround and are building your container by hand you are doing it wrong. So let\'s take a look how you can automate your container building on the excellent sourcehut infrastructure.
For this tutorial we will use the following workflow:
Creating the Dockerfile --> Commiting to git.sr.ht --> Building and tagging the image via builds.sr.ht --> Pushing the image to a registry
As an example project i will be using my xdarkhttpd-docker project. Darkhttpd is a basic webserver originally written by Emil Mikulic. I am using a fork by Ryan M. Jacobs which supports basic auth and am extending it by adding some more mimetypes (for now).2
Step 1: Creating the Dockerfile
Since the main effort lies in creating the Dockerfile from which our image will be built we will take a closer look at that. At first i used Alpine as base image and compiled darkhttpd in it. This resulted in an image which was around 9 to 10 Mb in size. After trying to remove some bloat (something you should always strive for) i was able to reduce the image size to around 7 Mb by using a multi-stage build.
This method builds the binary in one container including all build dependencies and then copies the binary over into a second container. 7Mb is okayish but we can go even smaller. If we are able to build a static binary we can use an empty image (called scratch) to house and run the binary and a work directory. Which is what i did. The whole xdarkhttpd image is now \< 700kB in size. (I have to add that darkhttpd in itself is a very rudimentary server. No cgi, no dynamic content, etc.)
Without further ado here is the complete Dockerfile:
from alpine:latest as builder RUN apk --no-cache add make musl-dev git gcc run git clone https://github.com/ryanmjacobs/darkhttpd workdir darkhttpd copy filetype.patch . run patch darkhttpd.c < filetype.patch run LDFLAGS=-static make bin from scratch LABEL maintainer="firstname.lastname@example.org" expose 8080 #workdir /usr/local/bin copy --from=builder /darkhttpd/darkhttpd . workdir /data entrypoint ["../darkhttpd", ".", "--port", "8080"]
Normally i would commit this Dockerfile and the
filetype.patch to a
github repo and would connect my Docker Hub Account to it. Then i would
add a build job on Docker Hub and it would pull everything from the repo
build the image and then commit it to the registry. But we are here to
talk about how we would achieve the same on sourcehut. Cue the next
2. Create a .build.yml to tell builds.sr.ht what to do
Sourcehut has no interface to configure the build system. Instead it relies on a YAML-file which you can add to your repository. I will publish my .build.yml and then will talk about some aspects which are not intuitive (not because of sourcehut but the whole process).
image: fedora/30 packages: - buildah sources: - https://git.sr.ht/~containsliquid/xdarkhttpd-docker secrets: - b525cc29-e3ad-488e-8b07-f267e3db3532 tasks: - build_image: | cd xdarkhttpd-docker buildah bud -f Dockerfile -t containsliquid/xdarkhttpd:latest - push_image: | buildah login docker.io buildah push --format docker containsliquid/xdarkhttpd:latest docker://docker.io/containsliquid/xdarkhttpd:latest
I won\'t go into too much details since there is enough documentation and references on sourcehut for this matter. One of the biggest changes in the standard workflow is that i am not using Docker to build the image. But why? Docker, even though they are one of the two big players in the field of containerization, has a few drawbacks. And especially two of them are pretty annoying in this case:
- The need for root to buld and run containers, which can cause problems in build environments3
- You need external repositories to have an up-to-date version of docker
Since it is my goal to make the process as simple as possible i opted in
to use Buildah instead. Buildah is a tool
developed by Redhat and is following the OCI specification for container
images. Buildah does not require root to run and is also part of the
standard Fedora/Centos repos. Buildah works very similar to Docker. So
we do not need to change things in our Dockerfile. With the command in
we are building and tagging the image. After the
build_image task we
push_image task. We log into Docker Hub and push the image
to the repo there. Easy right?
3. Hurdles in the process
3.1. Docker Hub Login
This one is a bit tricky. The login process of Buildah requires you to
pass your credentials either via
--username & --password or via
authfile. Usually this file is located in
Luckily enough you can add secrets on sourcehut. At this time sourcehut
supports ssh-, pgp-keys and files as secrets. So log into the registry
of your choice on your local machine (Docker or Podman/Buildah will
work). Locate the corresponding
config.json and add it to the
sourcehut secret store. Remember to add the correct path for the file so
Buildah can find the file. You are now able to log into the registry on
3.2. The weird OCI compatibility of Docker Hub
This is something which completely is the fault of Docker Inc.
- Their registry on hub.docker.com is a V1 registry which means that it does not work with software that is following the OCI specification.4 This problem can be circumvented by using docker.io as base domain (which is an interface for the newer registry V2).
- Pushing an OCI compliant image to docker.io works in Buildah but the
image won\'t show in the web ui. This is a weird one. I don\'t know
if currently their registry or the frontend is broken. But you can
--format dockerflag to your push command and everything is working fine.
Sourcehut is an excellent environment to build and deploy container images. There are a few things to consider but all in all the workflow is not that different to github. The major benefit of using sourcehut over github is independance from the big silos. Furthermore sourcehuts buildsystem offers more flexibility than Dockers own system. One thing i will look into in the future is automated inspection and analysis of images. So stay tuned...
Isolation in this context is mainly referring to bundeling dependencies not security. ↩
Thus calling it e(x)tended darkhttpd or shor xdarkhttpd. I am awul at naming thing. ↩
I never tested it, but i think docker would work fine on sourcehut. But i wanted to show an approach that could potentially work everywhere and does not rely on the right privileges to talk to daemon running as root. ↩
V1 was Dockers own format for container images. Since the format has been specified by the Open Container Initiative version 2 of their registry is compatible with OCI compliant images. ↩