Creating and Publishing a Docker Image

· jswank's blog

Using Sourcehut to publish a docker image to ghcr.io.
#sourcehut #ghcr #ci

I needed to get a docker image created and available publicly . I decided to experiment by using the Sourcehut build system and Github's container registry to publish the image whenever changes are commited to the repo.

A mechanism for creating and publishing my image from the shell was already complete. I use just as make analog for this sort of thing, and my hope was to use this approach with Sourcehut.

# Table of Contents

# Platform Info

# ghcr.io

Here is the reference doc for ghcr.io. It boils down to:

  1. Creating a personal access token (PAT) with permissions sufficient to publish images.
  2. Using that personal access token and the docker command to login and publish the image.
  3. Remembering that the first time a package is published, its visibility will be private.

# Sourcehut Builds

The user manual is short and sweet. Using a YAML file called .build.yml, the information required to configure the build agent (like base image, list of packages, source files, secrets) is supplied. Tasks for the build are Bash scripts. I'll need to:

  1. Install & configure build dependencies.
  2. Run the build.
  3. Use the secret GitHub PAT to publish the image.

# Step by Step

# Create the GH personal access token

A personal access token with scopes=write:packages needs to be created. There is a UI bug which prevents minimal permssions like this from being selected (as documented in the container registry reference doc.

Use this link https://github.com/settings/tokens/new?scopes=write:packages to create a personal access token with the minimal permissions.

# Create a Sourcehut secret

Sourcehut secrets are managed at https://builds.sr.ht/secrets. Unlike some other build systems which expose secrets as environment variables, Sourcehut presents secrets to build agents as files. I configured this secret to reside in the file ~/.envdir/GH_PAT.

![[Pasted image 20230227161442.png]]

# Create the build manifest

Here is my build manifest, .build.yml, which should be created at the root of the git repository.

 1image: alpine/edge
 2
 3secrets:
 4  - 0ee986ff-5686-43cd-ac3a-1fe5b2e5dd8f
 5
 6sources:
 7  - https://git.sr.ht/~jswank/alpine-cli
 8
 9packages:
10  - podman  # required to buuld / publish image
11  - just    # the task runner 
12  - runit   # includes chpst for env var handling
13
14tasks:
15  # cgroups need to be running in order to run podman
16  - prep: |
17      sudo rc-service cgroups start
18      sleep 1      
19
20  # build the image using the just recipe
21  #   - sudo (-u root) is required to run podman without more setup
22  - build: |
23      cd alpine-cli
24      sudo just build      
25
26  # publish the image using the just recipe
27  #   - set environment variables from the ~/.envdir directory. see
28  #   http://smarden.org/runit/chpst.8.html for details on chpst
29  #   - sudo (-u root) is required to run podman without more setup
30  #   - sudo --preserve-env is required to pass environment variables 
31  - publish: |
32      cd alpine-cli
33      chpst -e ~/.envdir \      
34	      sudo --preserve-env \
35		      just registry_pass_var=GH_PAT publish

My build process uses podman to create and publish the container: in addition to installing that package on the build agent, some setup needs to happen to make it work. I did the minimal amount of setup - and did not configure the build agent to support non-root podman usage. I.e. the build and publish steps need to run as root.

The build task executes the just recipe build. It is invoked by sudo so that podman will function.

The publish task executes the just recipe publish. An environment variable $GH_PAT needs to be set - the venerable chpst command is used to accomplish this by making use of the secret written to ~/.envdir/GH_PAT.

# Perform the build

When content is pushed to a Sourcehut repo containing a .build.yml, a build will occur. There are alternative ways to trigger a build that do not require a push - for instance, a manifest can be submitted via the ui or via the API.

# Make the image publicly available

After some trial and error, my image was published to ghcr.io - but was not available publicly. I went to https://github.com/users/jswank/packages/container/alpine-cli/ and updated the settings to make the package visible.

# More Info