improved version

This commit is contained in:
Worph
2026-10-03 17:24:49 +02:00
parent b5224cb512
commit d21e5d93ed
+41 -12
View File
@@ -7,8 +7,8 @@ name: ipcr-forge
# → radicle-gitea-bridge copies repos that commit .gitea/workflows/ # → radicle-gitea-bridge copies repos that commit .gitea/workflows/
# → gitea + gitea-runner GitHub-style Actions build the image # → gitea + gitea-runner GitHub-style Actions build the image
# → gitea registry staging: gitea-<domain>/gitea_admin/<app>:1.2.3 # → gitea registry staging: gitea-<domain>/gitea_admin/<app>:1.2.3
# ┄ (not wired yet) package webhook → IPCR import # → ipcr-gateway follows Gitea's registry imports every tag into IPFS, publishes IPNS
# → ipcr-kubo / ipcr-registry / ipcr-gateway # → ipcr-kubo / ipcr-registry
# docker pull ipcr.localhost:4767/ipns/<name>:1.2.3 (anyone) # docker pull ipcr.localhost:4767/ipns/<name>:1.2.3 (anyone)
# #
# Every service is copied verbatim from its standalone listing (apps/Radicle, apps/Gitea, # Every service is copied verbatim from its standalone listing (apps/Radicle, apps/Gitea,
@@ -18,9 +18,10 @@ name: ipcr-forge
# Replaces those four apps; it cannot sit beside them. It uses the same container names, # Replaces those four apps; it cannot sit beside them. It uses the same container names,
# domains (radicle-, radicle-api-, gitea-) and host ports (8776, 4768, 127.0.0.1:4767). # domains (radicle-, radicle-api-, gitea-) and host ports (8776, 4768, 127.0.0.1:4767).
# #
# The handoff from Gitea's registry to IPFS is the one missing link: the runner's jobs run in # The handoff from Gitea's registry to IPFS is a pull, run by IPCR: the runner's jobs run in a
# a nested Docker that cannot reach ipcr.localhost (it is the *host's* loopback), so the # nested Docker that cannot reach ipcr.localhost (the *host's* loopback), so CI never pushes to
# import has to run on IPCR's side, triggered by Gitea's "package published" webhook. # IPCR. Instead ipcr-gateway polls gitea:3000 over gitea-internal, with a read-only token the
# bridge-credentials step mints. Gitea does not know IPCR exists.
services: services:
# ═══ Radicle — the source of truth ═════════════════════════════════════════════ # ═══ Radicle — the source of truth ═════════════════════════════════════════════
@@ -326,7 +327,7 @@ services:
# ipcrd: TLS front door on 127.0.0.1:4767. Passes /ipfs/<cid> through to the stock nerdctl # ipcrd: TLS front door on 127.0.0.1:4767. Passes /ipfs/<cid> through to the stock nerdctl
# registry below, resolves /ipns/<name>:<tag> itself, and pins every image it serves. # registry below, resolves /ipns/<name>:<tag> itself, and pins every image it serves.
ipcr-gateway: ipcr-gateway:
image: ghcr.io/yundera/ipcr:0.1.0 image: ghcr.io/yundera/ipcr:1.1.0
container_name: ipcr-gateway container_name: ipcr-gateway
# Root for one reason: it writes its CA into the host's Docker trust store (the narrow # Root for one reason: it writes its CA into the host's Docker trust store (the narrow
# bind below), which is root-owned. See rationale.md. # bind below), which is root-owned. See rationale.md.
@@ -343,8 +344,25 @@ services:
CA_EXPORT: /certs.d/ipcr.localhost:4767/ca.crt CA_EXPORT: /certs.d/ipcr.localhost:4767/ca.crt
# Pin every image this host pulls, so the node keeps — and re-shares — what it runs. # Pin every image this host pulls, so the node keeps — and re-shares — what it runs.
AUTO_PIN: "true" AUTO_PIN: "true"
# Optional: follow a registry. Every tag of every repository it lists (or of
# IPCR_IMPORT_REPOS) is copied into IPFS and published as /ipns/<owner-repo>:<tag>;
# a tag is re-imported when it moves. Empty = off. IPCR_IMPORT_AUTH is user:token,
# a read-only (read:package) token is enough.
# Forge: watch this app's own Gitea, over gitea-internal (not through Caddy).
IMPORT_WATCH: ${IPCR_IMPORT_WATCH:-http://gitea:3000}
IMPORT_AUTH: ${IPCR_IMPORT_AUTH:-}
# Forge: a read:package token the bridge-credentials step mints. Re-read every poll
# and preferred over IMPORT_AUTH, so it may appear after the gateway is up.
IMPORT_AUTH_FILE: /data/secrets/registry-auth
IMPORT_REPOS: ${IPCR_IMPORT_REPOS:-}
IMPORT_INTERVAL: 60s
STATE_DIR: /data/state
volumes: volumes:
- ${DATA_ROOT:-/DATA}/AppData/$AppID/ipcr/tls:/data/tls - ${DATA_ROOT:-/DATA}/AppData/$AppID/ipcr/tls:/data/tls
# What the watcher already imported (tag → manifest digest).
- ${DATA_ROOT:-/DATA}/AppData/$AppID/ipcr/state:/data/state
# Forge only: the credential above. Read-only here.
- ${DATA_ROOT:-/DATA}/AppData/$AppID/ipcr/secrets:/data/secrets:ro
# The host's Docker trust store, so the CA above can be dropped into it: no daemon # The host's Docker trust store, so the CA above can be dropped into it: no daemon
# reload, no daemon.json edit. The parent is mounted because Compose cannot create a # reload, no daemon.json edit. The parent is mounted because Compose cannot create a
# bind source whose name contains a colon (ipcr.localhost:4767). ipcrd writes exactly # bind source whose name contains a colon (ipcr.localhost:4767). ipcrd writes exactly
@@ -364,6 +382,8 @@ services:
start_period: 10s start_period: 10s
networks: networks:
- ipcr-internal - ipcr-internal
# Forge only: reaches gitea:3000 for the import poller above.
- gitea-internal
cpu_shares: 50 cpu_shares: 50
deploy: deploy:
resources: resources:
@@ -373,7 +393,7 @@ services:
# ── Stock nerdctl IPFS registry ───────────────────────────────────────────── # ── Stock nerdctl IPFS registry ─────────────────────────────────────────────
# `nerdctl ipfs registry serve`, unmodified: translates the registry API into IPFS reads. # `nerdctl ipfs registry serve`, unmodified: translates the registry API into IPFS reads.
ipcr-registry: ipcr-registry:
image: ghcr.io/yundera/ipcr:0.1.0 image: ghcr.io/yundera/ipcr:1.1.0
container_name: ipcr-registry container_name: ipcr-registry
# Root because nerdctl run as any other uid assumes rootless mode and refuses to start # Root because nerdctl run as any other uid assumes rootless mode and refuses to start
# without a rootless containerd — which `ipfs registry serve` never uses. The service has # without a rootless containerd — which `ipfs registry serve` never uses. The service has
@@ -515,8 +535,9 @@ x-casaos:
**Ports.** TCP 8776 (Radicle peers) and 4768 TCP+UDP (IPFS peers) are published. **Ports.** TCP 8776 (Radicle peers) and 4768 TCP+UDP (IPFS peers) are published.
**Not wired yet:** images reach Gitea's registry automatically, but publishing them to **Images reach IPFS on their own.** IPCR follows this app's Gitea registry: about a
IPFS is still a manual `ipcr push` (see the IPCR README). minute after a build pushes `gitea_admin/<repo>:<tag>`, it can be pulled as
`ipcr.localhost:4767/ipns/gitea_admin-<repo>:<tag>`.
fr_fr: | fr_fr: |
**Remplace quatre applications.** Désinstallez d'abord Radicle, Gitea, Radicle Gitea **Remplace quatre applications.** Désinstallez d'abord Radicle, Gitea, Radicle Gitea
Bridge et IPCR : cette application utilise les mêmes adresses et ports. Bridge et IPCR : cette application utilise les mêmes adresses et ports.
@@ -530,8 +551,9 @@ x-casaos:
**Ports.** TCP 8776 (pairs Radicle) et 4768 TCP+UDP (pairs IPFS) sont publiés. **Ports.** TCP 8776 (pairs Radicle) et 4768 TCP+UDP (pairs IPFS) sont publiés.
**Pas encore relié :** les images arrivent automatiquement dans le registre Gitea, mais **Les images arrivent sur IPFS d'elles-mêmes.** IPCR suit le registre Gitea de cette
leur publication sur IPFS reste un `ipcr push` manuel (voir le README d'IPCR). application : environ une minute après qu'un build a poussé `gitea_admin/<dépôt>:<tag>`,
elle se tire avec `ipcr.localhost:4767/ipns/gitea_admin-<dépôt>:<tag>`.
index: / index: /
webui_port: 8080 webui_port: 8080
store_app_id: ipcr-forge store_app_id: ipcr-forge
@@ -580,6 +602,11 @@ x-compose-app:
- path: /DATA/AppData/$AppID/ipcr/init.d - path: /DATA/AppData/$AppID/ipcr/init.d
user: $PUID user: $PUID
group: $PGID group: $PGID
# Written by bridge-credentials as $PUID, read by ipcr-gateway (root).
- path: /DATA/AppData/$AppID/ipcr/secrets
user: $PUID
group: $PGID
mode: "0700"
files: files:
# Each entry and its reason are in the standalone listing it comes from. # Each entry and its reason are in the standalone listing it comes from.
- path: /DATA/AppData/$AppID/radicle/home/config.json - path: /DATA/AppData/$AppID/radicle/home/config.json
@@ -649,10 +676,12 @@ x-compose-app:
network: $APP_NET network: $APP_NET
volumes: volumes:
- /DATA/AppData/$AppID/bridge/secrets:/secrets - /DATA/AppData/$AppID/bridge/secrets:/secrets
- /DATA/AppData/$AppID/ipcr/secrets:/ipcr-secrets
# Also mints IPCR's read-only token for following Gitea's registry.
command: command:
- sh - sh
- -c - -c
- GITEA_PASSWORD="$APP_DEFAULT_PASSWORD" bridge-init - GITEA_PASSWORD="$APP_DEFAULT_PASSWORD" IPCR_AUTH_FILE=/ipcr-secrets/registry-auth bridge-init
when: absent:/DATA/AppData/$AppID/bridge/secrets/gitea-token when: absent:/DATA/AppData/$AppID/bridge/secrets/gitea-token
webui-host: radicle-${domain} webui-host: radicle-${domain}
webui-path: / webui-path: /