alpine-cgit
MultiArch Alpine Linux + S6 + cGit + SSHd for network-local repositories.
This image containerizes cGit running under a LigHttpd server to serve locally hosted git repositories. Can also be used to clone and push/pull the repos using git via SSH/PubKey authentication. Scripts included to ease the tasks of creating or mirroring bare repositories, or to sync them periodically.
Based on Alpine Linux (v3.23) from the s6 image with the cgit package installed in it.
Get the Image¶
Pull the image from Docker Hub.
Image Tags
The image is tagged respectively for the following architectures,
latest tag is annotated as multiarch so pulling without specifying any architecture tags should fetch the correct image for your architecture. Same goes for any of the version tags.
non-x86_64 images used to contain the embedded qemu-user-static binary which has been redundant for a while, and is being deprecated starting with our Alpine Linux v3.22 base-image release, see qemu-user-static or the more recent binfmt instead for running multi-arch containers.
Run¶
Running the container starts the service.
docker run --rm \
--name docker_cgit \
-p 64801:80 -p 64822:22 \
-v $PWD/data/git`#(1)`:/home/git \
-v $PWD/data/repositories`#(2)`:/home/git/repositories \
-v $PWD/data/ssh`#(3)`:/etc/ssh \
-v $PWD/data/web`#(4)`:/var/www \
woahbase/alpine-cgit
- Path to git user homedir, ssh-configurations generated/persisted here.
- (Required) Path to repositories storage root directory.
- (Required) If you want the host keys to persist.
- (Optional) Path to web-ui customization files directory.
Multi-Arch Support
If you want to run images built for other architectures on the same host (e.g. a x86_64 machine), you will need to have the specific binary format support configured on your host machine before running the image (otherwise you get an exec format error). Here's how,
For recent images, we can use tonistiigi's binfmt image to register binary execution support for the target architecture, like the following,
Architecture is that of the image we're trying to run, can be arm64 for aarch64, arm for both armv7l and armhf, or amd64 for x86_64. See binfmt.
Previously, multiarch, had made it easy for us by packing qemu into an image, so we could just run
However, that image (see qemu-user-static) seems to have fallen behind in updates, and with newer images the binfmt method is preferable.
Now images built for other architectures will also be executable. This is optional though, without the above, you can still run the image that is specifically made to support your host architecture.
Configuration¶
We can customize the runtime behaviour of the container with the following environment variables.
| ENV Vars | Default | Description |
|---|---|---|
| CGIT_HOSTNAME | localhost | Hostname to set in the url for cloning via web or ssh. |
| CGIT_SUBPATH | unset | Alternate virtual-root for CGit repositories, can be "" (unset or empty-string for serving at root path) or a path like /git or /repos, but cannot be "/" (single backslash) or /cgit. (since 1.2.3_20250702) Previously defaulted to /git. |
| CGIT_REPODIR | /home/git/repositories | Default path to repositories. (since 1.2.3_20240907) |
| CGIT_ARCHIVEDIR | ${CGIT_REPODIR}/.archived | Default path to archived repos (used in backup/restore scripts). (since 1.2.3_20240907) |
| CGIT_SKIP_PERMFIX | unset | If set to a non-empty-string value (e.g. 1), skips fixing permissions for cgit configuration files/directories. (since 1.2.3_20250702) |
| CGIT_PERMFIX_REPOS | unset | If set to true, will fix repositories permissions to ${S6_USER} (default git:git). (since 1.2.3_20240907) |
| CGIT_GIT_CONFIG | /home/git/.gitconfig | Customizable configurations for git. (used in scripts) (since 1.2.3_20250311) |
| CGIT_HOOKSDIR | /defaults/hooks | Custom hooks to add into repositories created via the bareinit or mirror script. (since 1.2.3_20240907) |
| CGIT_HOOKS | unset | Comma-separated list of hooks to add into repositories created via the bareinit or mirror script. e.g. "post-receive,post-update". (Previously all hooks in ${CGIT_HOOKSDIR} were copied) If any hook listed here is not found, the default hook from the (repository-name)/hooks directory is copied instead.(since 1.2.3_20250311) |
| CGIT_REPOS_MAXDEPTH | 3 | Maximum depth to search for repositores, (used in scripts). (since 1.2.3_20250311) |
| CGIT_SYNC_RUNFILE | /tmp/sync_is_running | File indicator that a sync job is already running. (used in sync script) (since 1.2.3_20240907) |
| CGIT_SYNC_LIST | /tmp/sync_list_of_repos | List of repositories to sync, generated at start of sync job. (used in sync script) (since 1.2.3_20240907) |
| CGIT_SYNC_IGNORELIST | ${CGIT_REPODIR}/ignored.txt | List of repositories to ignore while sync. (format: (category)/(repo-name).git) (used in sync script) (since 1.2.3_20240907) |
| CGIT_SYNC_ERRORLIST | ${CGIT_REPODIR}/errors.txt | Catches errors encountered while sync. Flushed on each run. (used in sync script) (since 1.2.3_20240907) |
| CGIT_SYNC_JOBS | 1 | Number of threads used by git to sync a repository. (since 1.2.3_20240907) |
| CGIT_SYNC_FSCK | false | If set to true, the sync script runs a git fsck before fetch for all repositories. Alternately, create a file named SYNC_NEED_FSCK in a repository to enable just for that repository. (since 1.2.3_20250311) |
| CGIT_SYNC_REPACK | false | If set to true, the sync script runs a git repack after fetch for all repositories. Alternately, create a file named SYNC_NEED_REPACK in a repository to enable just for that repository. (since 1.2.3_20250311) |
| LIGHTTPD_CONFDIR | /etc/lighttpd | Path to lighttpd configuration directory. (since 1.2.3_20240907) |
| LIGHTTPD_LOGFILE | /var/log/lighttpd/lighttpd.log | Logfile for lighttpd, by default logs both access and error logs. (since 1.2.3_20240907) |
| LIGHTTPD_USER | lighttpd | Non-root user that lighttpd drops privileges to. (since 1.2.3_20240907) |
| LIGHTTPD_ARGS | -D | Customizable arguments passed to lighttpd service. |
| LIGHTTPD_SKIP_LOGFIFO | unset | By default lighttpd logs to stdout via a fifo, set this to true to log to a regular file instead. (since 1.2.3_20240907) |
| SSHD_CONFDIR | /etc/ssh | Path to ssh server configuration directory. (since 1.2.3_20240907) |
| SSHD_ARGS | -De | Customizable arguments passed to sshd service. |
| SSHD__(parameter) | unset | If set, will update the parameter (if exists) with the value in sshd_config. E.g. SSHD__Port=2222. (Note the double underscores.) (since 1.2.3_20240907) |
| S6_NEEDED_PACKAGES | empty string | Space-separated list of extra APK packages to install on start. E.g. "curl git tzdata" |
| PUID | 1000 | Id of ${S6_USER}. |
| PGID | 1000 | Group id of ${S6_USER}. |
| S6_USER | git | (Preset) Default non-root user for services to drop privileges to. |
| S6_USERHOME | /home/git | (Preset) HOME directory for ${S6_USER}. |
Did you know?
You can check your own UID/GID by running the command id in a terminal.
Also,
-
Default configuration listens to ports
80and22(ssh), these may be published at64801and64822by default, so they don't clash with other services. -
Configuration file for CGit is at
/etc/cgitrc, edit or remount this with your own. A sample is provided in/defaults, this gets copied when no such file exists before service is started. -
Configuration file for Lighttpd is at
/etc/lighttpd/lighttpd.conf, edit or remount this with your own. A sample is provided in/defaults, this gets copied when no such file exists before service is started. (since 1.2.3_20240907) -
By default, cGit is deployed using the root path example at the root path
/, (since 1.2.3_20250702). If you need your repositories served at a subpath like/git/, set${CGIT_SUBPATH}to a non-empty-string e.g/git, that will use the subpath example instead to deploy the service at/cgit, and aliased to/git/for convenience. Of course this only applies if any custom file${LIGHTTPD_CONFDIR}/cgit.confdoes not already exist. -
Configuration file for SSH server is at
/etc/ssh/sshd_config, edit or remount this with your own. A sample is provided in/defaults, this gets copied when no such file exists before service is started. -
To persist the same SSH host keys, preserve their contents at
/etc/ssh. These are re-generated if not found. -
Only allows pubkey authentication by default, either use the one for the user git, or add your own in
/home/git/.ssh/authorized_keysto get clone and push/pull access. Default adds only the pubkey of thegituser, if that does not exist, a new set of private/public keys are generated. -
Repositories stored at
/home/git/repositories, can be changed via setting the${CGIT_REPODIR}environment variable. -
Web specific stuff, e.g
about.htmlor syntax filters should be inside/var/www, cgit provides some default filters (not used) located at/usr/lib/cgit/. Mount or configure your own if that's what you need.
Scripts¶
A few scripts for common tasks are baked into the image, E.g. we can create a bare repository with,
Mirror a copy of an existing online repository locally with,
Sync the repositories already tracking with their remote,
Backup a bare or mirror repository to ${CGIT_ARCHIVEDIR}/(optional category-dir)/repo-name, (since 1.2.3_20240907)
Restore a backed-up repository from ${CGIT_ARCHIVEDIR}/(optional category-dir)/repo-name, (since 1.2.3_20240907)
Stop the container with a timeout, (defaults to 2 seconds)
Restart the container with
Removes the container, (always better to stop it first and -f only when needed most)
Shell access¶
Get a shell inside a already running container,
Optionally, login as a non-root user, (default is git)
Or set user/group id e.g 1000/1000,
Logs¶
To check logs of a running container in real time
As-A-Service¶
Run the container as a service with the following as reference (and modify it as needed).
With docker-compose (alpine-cgit.yml)
---
services:
cgit:
container_name: cgit
deploy:
resources:
limits:
cpus: '2.00'
memory: 2048M # may need more memory for sync job
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 5
window: 120s
environment:
# CGIT_REPODIR: /home/git/repositories
# CGIT_SYNC_IGNORELIST: /home/git/repositories/ignored.txt
# CGIT_SYNC_ERRORLIST: /home/git/repositories/errors.txt
# CGIT_SYNC_JOBS: 1
PUID: ${PUID:-1000}
PGID: ${PGID:-1000}
# TZ: ${TZ}
# healthcheck:
# interval: 2m
# retries: 5
# start_period: 5m
# test:
# - CMD-SHELL
# - >
# curl -f http://localhost:80/git/ || exit 1
# timeout: 20s
hostname: cgit
image: woahbase/alpine-cgit:${CGIT_TAG:-latest}
network_mode: bridge
ports:
- protocol: tcp
host_ip: 0.0.0.0
published: ${CGIT_PORT_SSH:-22}
target: 22
- protocol: tcp
host_ip: 0.0.0.0
published: ${CGIT_PORT_HTTP:-80}
target: 80
volumes:
- type: bind
source: ${CGIT_DIR:?err}/git
target: /home/git
bind:
create_host_path: true
- type: bind
source: ${CGIT_DIR:?err}/repositories
target: /home/git/repositories
bind:
create_host_path: true
- type: bind
source: ${CGIT_DIR:?err}/ssh
target: /etc/ssh
bind:
create_host_path: true
# - type: bind
# source: ${CGIT_DIR:?err}/configs/cgitrc
# target: /etc/cgitrc
# bind:
# create_host_path: false
# - type: bind
# source: ${CGIT_DIR:?err}/configs/scripts
# target: /config/scripts
# bind:
# create_host_path: false
# - type: bind
# source: ${CGIT_DIR:?err}/configs/web
# target: /var/www
# bind:
# create_host_path: false
- type: bind
source: /etc/localtime
target: /etc/localtime
read_only: true
bind:
create_host_path: false
With HashiCorp Nomad (alpine-cgit.hcl)
variables {
dc = "dc1" # to load the dc-local config file
pgid = 1000 # gid for docker
puid = 1000 # uid for docker
version = "1.2.3"
}
# locals { var = yamldecode(file("${var.dc}.vars.yml")) } # load dc-local config file
job "cgit" {
datacenters = [var.dc]
# namespace = local.var.namespace
priority = 80
# region = local.var.region
type = "service"
# vault { policies = ["nomad-kv-readonly"] }
group "docker" {
count = 1
restart {
attempts = 2
interval = "2m"
delay = "15s"
mode = "fail"
}
update {
max_parallel = 1
min_healthy_time = "10s"
healthy_deadline = "10m"
progress_deadline = "15m"
auto_revert = false
}
service {
name = NOMAD_JOB_NAME
port = "http"
tags = ["ins${NOMAD_ALLOC_INDEX}", attr.unique.hostname, "aid=${NOMAD_ALLOC_ID}", "urlprefix-/git"]
canary_tags = ["canary${NOMAD_ALLOC_INDEX}", "urlprefix-/c/git"]
check {
name = "${NOMAD_JOB_NAME}@${attr.unique.hostname}:${NOMAD_HOST_PORT_http}=>${NOMAD_PORT_http}"
type = "http"
path = "/git/?p=about"
interval = "60s"
timeout = "10s"
}
check_restart {
limit = 3
grace = "10m"
}
}
service {
name = "${NOMAD_JOB_NAME}-ssh"
port = "ssh"
tags = ["ins${NOMAD_ALLOC_INDEX}", attr.unique.hostname, "aid=${NOMAD_ALLOC_ID}", "host=git"]
canary_tags = ["canary${NOMAD_ALLOC_INDEX}"]
check {
name = "${NOMAD_JOB_NAME}@${attr.unique.hostname}:${NOMAD_HOST_PORT_http}=>${NOMAD_PORT_ssh}"
type = "tcp"
interval = "60s"
timeout = "10s"
}
check_restart {
limit = 3
grace = "10m"
}
}
ephemeral_disk { size = 128 } # MB
network {
# dns { servers = local.var.dns_servers }
port "http" {
static = 64801
to = 80
}
port "ssh" {
static = 64822
to = 22
}
}
volume "nomad-cgit-repos" {
type = "host"
read_only = false
source = "nomad-cgit-repos"
}
volume "nomad-cgit-hostkeys" {
type = "host"
read_only = false
source = "nomad-cgit-hostkeys"
}
volume "nomad-cgit-userkeys" {
type = "host"
read_only = false
source = "nomad-cgit-userkeys"
}
# volume "nomad-cgit-scripts" {
# type = "host"
# read_only = false
# source = "nomad-cgit-scripts"
# }
volume "nomad-cgit-web" {
type = "host"
read_only = false
source = "nomad-cgit-web"
}
task "cgit" {
driver = "docker"
config {
healthchecks { disable = true }
hostname = NOMAD_JOB_NAME
image = "${local.var.docker_registry.url}/woahbase/alpine-cgit:${var.version}"
network_mode = "bridge"
ports = ["http", "ssh"]
# volumes = [
# "/path/to/your/cgit/git/.ssh:/home/git/.ssh",
# "/path/to/your/cgit/scripts:/scripts",
# "/path/to/your/cgit/hooks:/defaults/hooks",
# "/path/to/your/cgit/ssh:/etc/ssh",
# "/path/to/your/cgit/web:/var/www"
# ]
logging {
type = "journald"
config {
mode = "non-blocking"
tag = NOMAD_JOB_NAME
}
}
mount {
source = "local/cgitrc"
target = "/etc/cgitrc"
type = "bind"
readonly = true
}
mount {
type = "bind"
target = "/etc/localtime"
source = "/etc/localtime"
readonly = true
}
}
volume_mount {
# ensure policies allow vault-generated-token to read-write to the volume
volume = "nomad-cgit-repos"
destination = "/home/git/repositories"
read_only = false
}
volume_mount {
volume = "nomad-cgit-hostkeys"
destination = "/etc/ssh"
read_only = false
}
# volume_mount {
# volume = "nomad-cgit-scripts"
# destination = "/scripts"
# read_only = true
# }
volume_mount {
volume = "nomad-cgit-userkeys"
destination = "/home/git/.ssh"
read_only = false
}
volume_mount {
volume = "nomad-cgit-web"
destination = "/var/www"
read_only = true
}
env {
PGID = var.pgid
PUID = var.puid
# TZ = local.var.tz
}
resources {
cpu = 1536 # MHz
memory = 2048 # MB
}
template {
change_mode = "restart"
destination = "local/cgitrc"
data = <<-EOC
{{ key "nomad/${var.dc}/cgit/cgitrc" }}
EOC
error_on_missing_key = true
}
}
}
}
Reverse Proxy¶
To proxy it through a web server, see below
This snippet can be used to reverse-proxy the service using NGINX.
upstream proxy_cgit {
server your.host.local:<cgit-port> fail_timeout=5;
}
## the following goes inside a server block
location /cgit { return 301 /cgit/; }
location /cgit/ {
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_redirect redirect replacement;
proxy_pass http://proxy_cgit;
}
location /git { return 301 /git/; }
location /git/ {
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_redirect redirect replacement;
proxy_pass http://proxy_cgit;
}
Build Your Own¶
Feel free to clone (or fork) the repository and customize it for your own usage, build the image for yourself on your own systems, and optionally, push it to your own public (or private) repository.
Here's how...
Setting up¶
Before we clone the /repository, we must have Git, GNU make, and Docker (optionally, with buildx plugin for multi-platform images) setup on the machine. Also, for multi-platform annotations, we might require enabling experimental features of Docker.
Now, to get the code,
Clone the repository with,
To get a list of all available targets, run
Always Check Before You Make!
Did you know, we could check what any make target is going to execute before we actually run them, with
Build and Test¶
To create the image for your architecture, run the build and test target with
For building an image that targets another architecture, it is required to specify the ARCH parameter when building. e.g.
Build Parameters
All images have a few common build parameters that can be customized at build time, like
ARCH
- The target architecture to build for. Defaults to host architecture, auto-detected at build-time if not specified. Also determines if binfmt support is required before build or run and runs the
regbinfmt(orinbinfmtfor recent images) target automatically. Possible values could beaarch64,armhf,armv7l, orx86_64.
BUILDDATE
- The date of the build. Can be used to create separate tags for images. (format:
yyyymmdd)
DOCKERFILE
- The dockerfile to use for build. Defaults to the file Dockerfile, but if per-arch dockerfiles exist, (e.g. for x86_64 the filename would be
Dockerfile_x86_64) that is used instead.
TESTCMD
- The command to run for testing the image after build. Runs in a bash shell.
VERSION
- The version of the app/tool, may need to be preset before starting the build (e.g. for binaries from github releases), or extracted from the image after build (e.g. for APK or pip packages).
REGISTRY
- The registry to push to, defaults to the Docker Hub Registry (
docker.io) or any custom registry that is set via docker configurations. Does not need to be changed for local or test builds, but to override, either pass it by setting an environment variable, or with everymakecommand.
ORGNAME
- The organization (or user) name under which the image repositories exist, defaults to
woahbase. Does not need to be changed for local or test builds, but to override, either pass it by setting an environment variable, or with everymakecommand.
The image may also require custom parameters (like binary architecture). Before you build, check the makefile for a complete list of parameters to see what may (or may not) need to be set.
BuildX and Self-signed certificates
If you're using a private registry (a-la docker distribution server) with self-signed certificates, that fail to validate when pulling/pushing images. You will need to configure buildx to allow insecure access to the registry. This is configured via the config.toml file. A sample is provided in the repository, make sure to replace YOUR.PRIVATE.REGISTRY with your own (include port if needed).
Make to Run¶
Running the image creates a container and either starts a service (for service images) or provides a shell (can be either a root-shell or usershell) to execute commands in, depending on the image. We can run the image with
But if we just need a root-shell in the container without any fance pre-tasks (e.g. for debug or to test something bespoke), we can run bash in the container with --entrypoint /bin/bash. This is wrapped in the makefile as
Nothing vs All vs Run vs Shell
By default, if make is run without any arguments, it calls the target all. In our case this is usually mapped to the target run (which in turn may be mapped to shell).
There may be more such targets defined as per the usage of the image. Check the makefile for more information.
Push the Image¶
If the build and test steps finish without any error, and we want to use the image on other machines, it is the next step push the image we built to a container image repository (like /hub), for that, run the push target with
If the built image targets another architecture then it is required to specify the ARCH parameter when pushing. e.g.
Pushing Multiple Tags
With a single make push, we are actually pushing 3 tags of the same image, e.g. for x86_64 architecture, they're namely
alpine-cgit:x86_64
- The actual image that is built.
alpine-cgit:x86_64_${version}
- It is expected that the application is versioned when built or packaged, it can be specified in the tag, this makes pulling an image by tag possible. Usually this is obtained from the parameter
VERSION, which by default, is set by calling a function to extract the version string from the package installed in the container, or from github releases. Can be skipped with the parameterSKIP_VERSIONTAGto a non-empty string value like1.
alpine-cgit:x86_64_${version}_${builddate}
- When building multiple versions of the same image (e.g. for providing fixes or revisions), this ensures that a more recent push does not fully replace a previously pushed image. This way, although the architecture and version tags are replaced, it is possible to roll back to the previously built image by build date (format
yyyymmdd). This value is obtained from theBUILDDATEparameter, and if not essential, can be skipped by setting the parameterSKIP_BUILDDATETAGto a non-empty string value like1.
Pushing To A Private Registry
If you want to push the image to a custom registry that is not pre-configured on your system, you can set the REGISTRY variable either on the build environment, or as a makefile parameter, and that will be used instead of the default Docker Hub repository. Make sure to have push access set up before you actually push, and include port if needed. E.g.
or
Annotate Manifest(s)¶
For single architecture images, the above should suffice, the built image can be used in the host machine, and on other machines that have the same architecture too, i.e. after a push.
But for use-cases that need to support multiple architectures, there's a couple more things that need to be done. We need to create (or amend if already created beforehand) a manifest for the image(s) that we built, then annotate it to map the images to their respective architectures. And for our three tags created above we need to do it thrice.
Did you know?
We can inspect the manifest of any image by running
Tag Latest¶
Assuming we built the images for all supported architectures, to facilitate pulling the correct image for the architecture, we can create/amend the latest manifest and annotate it to map the tags :aarch64, :armhf, :armv7l, :i386, :ppc64le, :riscv64, :s390x, :x86_64 to the tag :latest by running
How it works
First we create or amend the manifest with the tag latest
docker manifest create --amend \
woahbase/alpine-cgit:latest \
woahbase/alpine-cgit:aarch64 \
woahbase/alpine-cgit:armhf \
woahbase/alpine-cgit:armv7l \
woahbase/alpine-cgit:i386 \
woahbase/alpine-cgit:ppc64le \
woahbase/alpine-cgit:riscv64 \
woahbase/alpine-cgit:s390x \
woahbase/alpine-cgit:x86_64 \
;
Then annotate the image for each architecture in the manifest with
And finally, push it to the repository using
Tag Version¶
Next, to facilitate pulling images by version, we create/amend the image-version manifest and annotate it to map the tags :aarch64_${version}, :armhf_${version}, :armv7l_${version}, :i386_${version}, :ppc64le_${version}, :riscv64_${version}, :s390x_${version}, :x86_64_${version} to the tag :${version} by running
How it works
First we create or amend the manifest with the tag ${version}
docker manifest create \
woahbase/alpine-cgit:${version} \
woahbase/alpine-cgit:aarch64_${version} \
woahbase/alpine-cgit:armhf_${version} \
woahbase/alpine-cgit:armv7l_${version} \
woahbase/alpine-cgit:i386_${version} \
woahbase/alpine-cgit:ppc64le_${version} \
woahbase/alpine-cgit:riscv64_${version} \
woahbase/alpine-cgit:s390x_${version} \
woahbase/alpine-cgit:x86_64_${version} \
;
docker manifest create --amend \
woahbase/alpine-cgit:${version} \
woahbase/alpine-cgit:aarch64_${version} \
woahbase/alpine-cgit:armhf_${version} \
woahbase/alpine-cgit:armv7l_${version} \
woahbase/alpine-cgit:i386_${version} \
woahbase/alpine-cgit:ppc64le_${version} \
woahbase/alpine-cgit:riscv64_${version} \
woahbase/alpine-cgit:s390x_${version} \
woahbase/alpine-cgit:x86_64_${version} \
;
Then annotate the image for each architecture in the manifest with
And finally, push it to the repository using
Tag Build-Date¶
Then, (optionally) we create/amend the ${version}_${builddate} manifest and annotate it to map the tags :aarch64_${version}_${builddate}, :armhf_${version}_${builddate}, :armv7l_${version}_${builddate}, :i386_${version}_${builddate}, :ppc64le_${version}_${builddate}, :riscv64_${version}_${builddate}, :s390x_${version}_${builddate}, :x86_64_${version}_${builddate} to the tag :${version}_${builddate} by running
How it works
First we create or amend the manifest with the tag ${version}_${builddate}
docker manifest create \
woahbase/alpine-cgit:${version}_${builddate} \
woahbase/alpine-cgit:aarch64_${version}_${builddate} \
woahbase/alpine-cgit:armhf_${version}_${builddate} \
woahbase/alpine-cgit:armv7l_${version}_${builddate} \
woahbase/alpine-cgit:i386_${version}_${builddate} \
woahbase/alpine-cgit:ppc64le_${version}_${builddate} \
woahbase/alpine-cgit:riscv64_${version}_${builddate} \
woahbase/alpine-cgit:s390x_${version}_${builddate} \
woahbase/alpine-cgit:x86_64_${version}_${builddate} \
;
docker manifest create --amend \
woahbase/alpine-cgit:${version}_${builddate} \
woahbase/alpine-cgit:aarch64_${version}_${builddate} \
woahbase/alpine-cgit:armhf_${version}_${builddate} \
woahbase/alpine-cgit:armv7l_${version}_${builddate} \
woahbase/alpine-cgit:i386_${version}_${builddate} \
woahbase/alpine-cgit:ppc64le_${version}_${builddate} \
woahbase/alpine-cgit:riscv64_${version}_${builddate} \
woahbase/alpine-cgit:s390x_${version}_${builddate} \
woahbase/alpine-cgit:x86_64_${version}_${builddate} \
;
Then annotate the image for each architecture in the manifest with
And finally, push it to the repository using
That's all folks! Happy containerizing!
Maintenance¶
Sources at Github. Built and tested at home using Buildbot. Images at Docker Hub.
Maintained (or sometimes a lack thereof?) by WOAHBase.
Helped you save a bit of your valuable time and effort that is best spent doing stuff you actually enjoy? If you have some pocket-change to spare, kindly consider helping out.