From d745f8399385bf6f469eec26cc483fe01fc3283b Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 20:49:51 -0500 Subject: [PATCH 01/10] add build stage for the spindle server --- Dockerfile | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 420fd7f..e500f5d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ from golang:1.25-alpine as builder -env KNOT_REPO_SCAN_PATH=/home/git/repositories env CGO_ENABLED=1 arg TAG='v1.11.0-alpha' @@ -7,9 +6,15 @@ arg TAG='v1.11.0-alpha' workdir /app run apk add git gcc musl-dev run git clone -b ${TAG} https://tangled.org/@tangled.org/core . -run go build -o /usr/bin/knot -ldflags '-s -w -extldflags "-static"' ./cmd/knot -from alpine:latest +FROM builder AS build-knot +RUN go build -o /usr/bin/knot -ldflags '-s -w -extldflags "-static"' ./cmd/knot + +FROM builder AS build-spindle +RUN go build -o /usr/bin/spindle ./cmd/spindle + +from alpine:latest AS knot +ENV KNOT_REPO_SCAN_PATH=/home/git/repositories expose 5555 expose 22 @@ -31,10 +36,34 @@ run groupadd -g $GID -f git run useradd -u $UID -g $GID -d /home/git git run openssl rand -hex 16 | passwd --stdin git run mkdir -p /home/git/repositories && chown -R git:git /home/git -copy --from=builder /usr/bin/knot /usr/bin +copy --from=build-knot /usr/bin/knot /usr/bin run mkdir /app && chown -R git:git /app healthcheck --interval=60s --timeout=30s --start-period=5s --retries=3 \ cmd curl -f http://localhost:5555 || exit 1 - entrypoint ["/init"] + +FROM alpine:edge AS spindle +EXPOSE 6555 + +LABEL org.opencontainers.image.title="spindle" +LABEL org.opencontainers.image.description="ci server for tangled" +LABEL org.opencontainers.image.source="https://tangled.org/@tangled.org/knot-docker" +LABEL org.opencontainers.image.url="https://tangled.org" +LABEL org.opencontainers.image.vendor="tangled.org" +LABEL org.opencontainers.image.licenses="MIT" + +ARG UID=1000 +ARG GID=1000 + +RUN groupadd --system -g $GID -f spindle +RUN useradd --system -u $UID -g $GID spindle +RUN mkdir -p /app && chown -R spindle:spindle /app + +COPY --from=build-spindle /usr/bin/spindle /usr/bin + +WORKDIR /app +CMD ["spindle"] +VOLUME ["/app"] +HEALTHCHECK --interval=60s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:6555 || exit 1 -- 2.51.2 From 3afc662e289613b94c7b296a0f309b44183ae1d0 Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 21:14:04 -0500 Subject: [PATCH 02/10] add spindle to docker-compose and configure builds for each image --- docker-compose.yml | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 558b19f..9bd1d36 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,16 @@ +name: tangled services: knot: + image: tngl/knot:latest build: - context: . + target: knot args: UID: 1000 GID: 1000 + TAG: ${TAG:-v1.11.0-alpha} + tags: + - tngl/spindle:latest + - tngl/spindle:${TAG:-v1.11.0-alpha} environment: KNOT_SERVER_HOSTNAME: ${KNOT_SERVER_HOSTNAME} KNOT_SERVER_OWNER: ${KNOT_SERVER_OWNER} @@ -19,15 +25,35 @@ services: - "5555:5555" - "2222:22" restart: always + spindle: + image: tngl/spindle:latest + build: + target: spindle + args: + UID: 1000 + GID: 1000 + TAG: ${TAG:-v1.11.0-alpha} + tags: + - tngl/spindle:latest + - tngl/spindle:${TAG:-v1.11.0-alpha} + environment: + SPINDLE_SERVER_HOSTNAME: ${SPINDLE_SERVER_HOSTNAME} + SPINDLE_SERVER_OWNER: ${KNOT_SERVER_OWNER} + volumes: + - ./logs:/var/log/spindle + - ./spindle:/app + ports: + - "6555:6555" frontend: image: caddy:alpine - command: > - caddy - reverse-proxy - --from ${KNOT_SERVER_HOSTNAME} - --to knot:5555 depends_on: - - knot + knot: + condition: service_healthy + spindle: + condition: service_healthy + configs: + - source: caddyfile + target: /etc/caddy/Caddyfile ports: - ${KNOT_SERVER_PORT:-443}:443 - ${KNOT_SERVER_PORT:-443}:443/udp @@ -35,3 +61,8 @@ services: - ./caddy_data:/data restart: always profiles: ["caddy"] +configs: + caddyfile: + content: | + ${KNOT_SERVER_HOSTNAME} { reverse_proxy knot:5555 } + ${SPINDLE_SERVER_HOSTNAME} { reverse_proxy spindle:6555 } -- 2.51.2 From b0a97c3e3c9237779dce2fa38b0c0e785095154d Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 21:14:18 -0500 Subject: [PATCH 03/10] add docker bake config for building edge releases --- docker-bake.hcl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docker-bake.hcl diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..cfd0824 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,19 @@ +group "edge" { + targets = ["knot-edge", "spindle-edge"] +} + +target "knot-edge" { + context = "." + args = { + TAG = "master" + } + tags = ["tngl/knot:edge"] +} + +target "spindle-edge" { + context = "." + args = { + TAG = "master" + } + tags = ["tngl/spindle:edge"] +} -- 2.51.2 From 62b69610153ed8912474a08528e0862ed85a880f Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 21:14:35 -0500 Subject: [PATCH 04/10] update readme to reference the spindle and document how to build images using docker bake --- readme.md | 57 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/readme.md b/readme.md index 11f7a33..cd73ede 100644 --- a/readme.md +++ b/readme.md @@ -4,42 +4,69 @@ > This is a community maintained repository, support is not guaranteed. Docker container and compose setup to run a [Tangled](https://tangled.org) knot -and host your own repository data. +and spindle, hosting your own repository data and CI. ## Pre-built Images -There is a [repository](https://hub.docker.com/r/tngl/knot) of pre-built images +There is a [repository](https://hub.docker.com/r/tngl) of pre-built images for tags starting at `v1.8.0-alpha` if you prefer. ``` docker pull tngl/knot:v1.10.0-alpha +docker pull tngl/spindle:v1.10.0-alpha ``` Note that these are *not* official images, you use them at your own risk. -## Building The Image +## Building The Images + +Both the knot and spindle images are built using the same `Dockerfile`, since +they're sourced from the same codebase and can therefore share a lot of the +build steps (such as `go mod download`), caching results between them. You +can build the images locally by running `docker bake`: + +```sh +docker bake +``` + +Optionally, choose a target image to build: + +```sh +docker bake knot +docker bake spindle +``` By default the `Dockerfile` will build the latest tag, but you can change it with the `TAG` build argument. ```sh -docker build -t knot:latest --build-arg TAG=master . +docker bake --build-arg TAG=v1.10.0-alpha ``` -The command above for example will build the latest commit on the `master` -branch. +The command above for example will build the `v1.10.0-alpha` tag. -By default it will also create a `git` user with user and group ID 1000:1000, +By default it will also create a `git` / `spindle` user with user and group ID 1000:1000, but you can change it with the `UID` and `GID` build arguments. ```sh -docker build -t knot:latest --build-arg UID=$(id -u) GID=$(id -g) +docker bake --build-arg UID=$(id -u) --build-arg GID=$(id -g) ``` The command above for example will create a user with the host user's UID and GID. This is useful if you are bind mounting the repositories and app folder on the host, as in the provided `docker-compose.yml` file. +You can also build the latest commit on `master` for both services by using +the `-edge` targets. These will build to a tag named `:edge` to distinguish +it from the `:latest` release: + +```sh +docker bake edge +# or, with a specific target image +docker bake edge-knot +docker bake edge-spindle +``` +
When using compose, these can be specified as build arguments which will be @@ -59,14 +86,16 @@ the command. ## Setting Up The Image -The simplest way to set up your own knot is to use the provided compose file -and run the following: +The simplest way to set up your own knot and spindle is to use the provided +compose file and run the following: ```sh -export KNOT_SERVER_HOSTNAME=example.com -export KNOT_SERVER_OWNER=did:plc:yourdidgoeshere -export KNOT_SERVER_PORT=443 -docker compose up -d +export KNOT_SERVER_HOSTNAME="knot.example.com" +export SPINDLE_SERVER_HOSTNAME="spindle.example.com" +export KNOT_SERVER_OWNER="did:plc:yourdidgoeshere" +export KNOT_SERVER_PORT="443" + +docker compose up --detach ``` This will setup everything for you including a reverse proxy. -- 2.51.2 From 1ded9865be4b85ac8f72ec6255323461184d84be Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 21:21:01 -0500 Subject: [PATCH 05/10] fix adduser/group commands in spindle stage --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e500f5d..1f2f794 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,8 +56,8 @@ LABEL org.opencontainers.image.licenses="MIT" ARG UID=1000 ARG GID=1000 -RUN groupadd --system -g $GID -f spindle -RUN useradd --system -u $UID -g $GID spindle +RUN adduser --system --uid $UID spindle +RUN addgroup --system --gid $UID spindle RUN mkdir -p /app && chown -R spindle:spindle /app COPY --from=build-spindle /usr/bin/spindle /usr/bin -- 2.51.2 From 321780496ecfed4b3ced886e0d847d3a4ecc3051 Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 21:40:52 -0500 Subject: [PATCH 06/10] add legacy releases task and info on how to build past releases --- docker-bake.hcl | 30 ++++++++++++++++++++++++++++++ docker-compose.yml | 11 ++++------- readme.md | 22 ++++++++++++++++------ 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/docker-bake.hcl b/docker-bake.hcl index cfd0824..86b1421 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -1,19 +1,49 @@ +variable "UID" { + default = "1000" +} + +variable "GID" { + default = "1000" +} + group "edge" { targets = ["knot-edge", "spindle-edge"] } target "knot-edge" { context = "." + target = "knot" args = { TAG = "master" + UID = UID + GID = GID } tags = ["tngl/knot:edge"] } target "spindle-edge" { context = "." + target = "spindle" args = { TAG = "master" + UID = UID + GID = GID } tags = ["tngl/spindle:edge"] } + +target "releases" { + name = "${APP}-${replace(TAG, ".", "-")}" + context = "." + matrix = { + APP = ["knot", "spindle"] + TAG = ["v1.11.0-alpha", "v1.10.0-alpha", "v1.9.0-alpha", "v1.8.0-alpha"] + } + target = "${APP}" + args = { + TAG = "${TAG}" + UID = UID + GID = GID + } + tags = ["tngl/${APP}:${TAG}"] +} diff --git a/docker-compose.yml b/docker-compose.yml index 9bd1d36..d6f28b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,9 +4,9 @@ services: image: tngl/knot:latest build: target: knot - args: - UID: 1000 - GID: 1000 + args: &args + UID: ${UID:-1000} + GID: ${GID:-1000} TAG: ${TAG:-v1.11.0-alpha} tags: - tngl/spindle:latest @@ -29,10 +29,7 @@ services: image: tngl/spindle:latest build: target: spindle - args: - UID: 1000 - GID: 1000 - TAG: ${TAG:-v1.11.0-alpha} + args: *args tags: - tngl/spindle:latest - tngl/spindle:${TAG:-v1.11.0-alpha} diff --git a/readme.md b/readme.md index cd73ede..c7983df 100644 --- a/readme.md +++ b/readme.md @@ -36,20 +36,28 @@ docker bake knot docker bake spindle ``` -By default the `Dockerfile` will build the latest tag, but you can change it -with the `TAG` build argument. +By default this will build the latest tag, but you can target a specific tag +like so: ```sh -docker bake --build-arg TAG=v1.10.0-alpha +docker bake knot-v1-10-0-alpha spindle-v1-10-0-alpha ``` -The command above for example will build the `v1.10.0-alpha` tag. +The command above for example will build the `v1.10.0-alpha` tag for both the +`knot` and `spindle`. They're expressed as individual bake targets, so you can +also optionally specify just one to build at a specific version. + +You can also build all tagged releases: + +```sh +docker bake releases +``` By default it will also create a `git` / `spindle` user with user and group ID 1000:1000, but you can change it with the `UID` and `GID` build arguments. ```sh -docker bake --build-arg UID=$(id -u) --build-arg GID=$(id -g) +docker bake UID=$(id -u) GID=$(id -g) ``` The command above for example will create a user with the host user's UID and GID. @@ -62,7 +70,9 @@ it from the `:latest` release: ```sh docker bake edge -# or, with a specific target image +# +# or, with a specific target image... +# docker bake edge-knot docker bake edge-spindle ``` -- 2.51.2 From e358d6f7bddb844dede59d0e067ee891a5c33032 Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Sat, 22 Nov 2025 21:57:21 -0500 Subject: [PATCH 07/10] rename releases to all --- docker-bake.hcl | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-bake.hcl b/docker-bake.hcl index 86b1421..4a5efde 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -32,7 +32,7 @@ target "spindle-edge" { tags = ["tngl/spindle:edge"] } -target "releases" { +target "all" { name = "${APP}-${replace(TAG, ".", "-")}" context = "." matrix = { diff --git a/readme.md b/readme.md index c7983df..168268d 100644 --- a/readme.md +++ b/readme.md @@ -50,7 +50,7 @@ also optionally specify just one to build at a specific version. You can also build all tagged releases: ```sh -docker bake releases +docker bake all ``` By default it will also create a `git` / `spindle` user with user and group ID 1000:1000, -- 2.51.2 From dcc096086060e8448595b2a30d6fd67090838115 Mon Sep 17 00:00:00 2001 From: Tom Scott Date: Wed, 17 Dec 2025 03:49:36 -0500 Subject: [PATCH 08/10] add docs around variables --- docker-bake.hcl | 31 ++++++++++++++----------------- readme.md | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/docker-bake.hcl b/docker-bake.hcl index 4a5efde..4bc1518 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -1,37 +1,34 @@ variable "UID" { default = "1000" + description = "User ID for the git and spindle users" } variable "GID" { default = "1000" + description = "Group ID for the git and spindle users" } -group "edge" { - targets = ["knot-edge", "spindle-edge"] -} - -target "knot-edge" { +# +# Build the latest commit from the master branch +# +target "edge" { + name = "${APP}-edge" context = "." - target = "knot" - args = { - TAG = "master" - UID = UID - GID = GID + target = "${APP}" + matrix = { + APP = ["knot", "spindle"] } - tags = ["tngl/knot:edge"] -} - -target "spindle-edge" { - context = "." - target = "spindle" args = { TAG = "master" UID = UID GID = GID } - tags = ["tngl/spindle:edge"] + tags = ["tngl/${APP}:edge"] } +# +# Build supported legacy releases +# target "all" { name = "${APP}-${replace(TAG, ".", "-")}" context = "." diff --git a/readme.md b/readme.md index 168268d..4853453 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ and spindle, hosting your own repository data and CI. There is a [repository](https://hub.docker.com/r/tngl) of pre-built images for tags starting at `v1.8.0-alpha` if you prefer. -``` +```sh docker pull tngl/knot:v1.10.0-alpha docker pull tngl/spindle:v1.10.0-alpha ``` -- 2.51.2 From 6aa81b9207d2f444eeac90b880a349019956f0e4 Mon Sep 17 00:00:00 2001 From: Bas van den Wollenberg Date: Mon, 23 Feb 2026 17:30:40 +0100 Subject: [PATCH 09/10] fix: add curl to spindle image --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 1f2f794..e8440a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,6 +56,7 @@ LABEL org.opencontainers.image.licenses="MIT" ARG UID=1000 ARG GID=1000 +run apk add curl bash RUN adduser --system --uid $UID spindle RUN addgroup --system --gid $UID spindle RUN mkdir -p /app && chown -R spindle:spindle /app -- 2.51.2 From 380990bbb9154e22310bf9945723f7cbeabf5307 Mon Sep 17 00:00:00 2001 From: Lewis Date: Thu, 2 Apr 2026 13:40:24 +0300 Subject: [PATCH 10/10] bump to v1.13.0-alpha Lewis: May this revision serve well! --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7142dae..566c472 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ from golang:1.25-alpine as builder env KNOT_REPO_SCAN_PATH=/home/git/repositories env CGO_ENABLED=1 -arg TAG='v1.12.0-alpha' +arg TAG='v1.13.0-alpha' workdir /app run apk add git gcc musl-dev -- 2.51.2