Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,15 @@ ansible-playbook content.yml --check --diff # dry run: reads DNSLink and the p
| lith-1 | `12D3KooWQSgVevfuy33SToBfYoCexqvvhgqYp8oGZ8r3CAesguRo` | `12D3KooWRcTH1HzbFt7UCSVaYScStt5wPr4bJo3aXHuvqPk6Gmgr` |
| chic-1 | `12D3KooWQ7PRw91uNk6e27NCym8CK1v39muL8omoDJzVsub3qZbV` | `12D3KooWKWfhxDGhs7DBgiqGmhCaj4SBoSbeEN2skHLbFsLZJCVS` |

**Images.** kubo and ipfs-cluster are pinned by digest in
`roles/content/defaults/main.yml` (`content_kubo_image`,
`content_cluster_image`). A box can set its own in `host_vars/<box>/content.yml`
to run a canary while the others stay on the release; deploy it with
`-l <box>`. sing-1 runs one now: kubo v0.43.1 with the go-libp2p inbound-slot
leak fix (see the comment there). A bootstrapper instance can do the same with
`kubo_image` in its `bootstrap_extra_instances` entry; chic-1's `bootstrap-b`
runs the same canary, with `bootstrap` on the same box as its control.

**Ports.**

| Port | Listener | Exposure |
Expand Down
15 changes: 14 additions & 1 deletion host_vars/chic-1/bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,18 @@ bootstrap_legacy_name: ny5
# Further kubo instances on this box, each with its own legacy identity.
# Ports come from bootstrap_instance_table (group_vars/ipfs_nodes); the
# key is vault_<name with - as _>_privkey in vault.yml.
#
# bootstrap-b runs the canary for the kubo inbound-slot leak
# (libp2p/go-libp2p#3564): the same image as sing-1's content node (see
# host_vars/sing-1/content.yml), ipfs/kubo v0.43.1 plus libp2p/go-libp2p#3568
# and nothing else. bootstrap on this box, the same traffic on the same box,
# stays on upstream v0.43.1 as its control. Remove kubo_image once a kubo
# release has the fix, or if the canary misbehaves, and re-run
# bootstrap.yml -l chic-1.
bootstrap_extra_instances:
- {name: bootstrap-b, peer_id: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN, legacy_name: sv15}
- name: bootstrap-b
peer_id: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
legacy_name: sv15
kubo_image:
name: ghcr.io/ipni/kubo
digest: sha256:44f66498beffd0136a9fe619ed109b29f8961488d6a8e7a492ccf0b4b065028c
13 changes: 13 additions & 0 deletions host_vars/sing-1/content.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,16 @@
# vault_content_kubo_privkey in vault.yml next to this file.
content_cluster_peer_id: 12D3KooWNzxaQEZCCw7c9RANwUieUbp9em6No7KrT45L3FLbAcsZ
content_kubo_peer_id: 12D3KooWDkwTCdWYVxnZCq6VYWsNjAGakCrqm7Zx3G2RSTR6dbsj

# Canary for the kubo inbound-slot leak (libp2p/go-libp2p#3564). The fix,
# libp2p/go-libp2p#3568, is merged (da148e11) but in no release. This image is
# ipfs/kubo v0.43.1 (acc53c0) built by kubo's own Dockerfile, with go-libp2p
# replaced by the module v0.43.1 already uses (lidel/go-libp2p@9c4ee60) plus
# that five-line fix, and nothing else: same dependencies, Go and build
# settings, and the same version string (0.43.1-acc53c0) as upstream. amd64
# only, pushed by hand on 2026-11-11. lith-1 and chic-1 stay on upstream
# v0.43.1 as the control. Remove this once a kubo release has the fix, or if
# the canary misbehaves, and re-run content.yml -l sing-1.
content_kubo_image:
name: ghcr.io/ipni/kubo
digest: sha256:44f66498beffd0136a9fe619ed109b29f8961488d6a8e7a492ccf0b4b065028c
11 changes: 6 additions & 5 deletions k8s/bootstrap/kustomization.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ labels:
app.kubernetes.io/name: bootstrap
app.kubernetes.io/part-of: ipfs-workers

# ipfs/kubo v0.43.1 (published 2026-09-15 00:52 UTC), multi-arch index, pinned by digest.
# Shipyard stops maintaining kubo on 2026-09-30: upgrades are deliberate, and
# go-libp2p / kubo security advisories need watching.
# Pinned by digest in roles/bootstrap/defaults/main.yml
# (bootstrap_default_kubo_image). An instance can run its own (kubo_image in
# its bootstrap_extra_instances entry): that is how one instance runs a canary
# while the others stay on the release.
images:
- name: kubo
newName: ipfs/kubo
digest: sha256:b293923d66e490e70ced64df42ea7a6cf7eac2740e3fb29101df18070fa7be48
newName: {{ bootstrap_kubo_image.name }}
digest: {{ bootstrap_kubo_image.digest }}

# The kubo config Secret (kubo-config) is deliberately NOT here: it holds the
# node's private key and is created by roles/bootstrap from ansible-vault.
32 changes: 0 additions & 32 deletions k8s/content/kustomization.yaml

This file was deleted.

29 changes: 29 additions & 0 deletions k8s/content/kustomization.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: content

resources:
- namespace.yaml
- pvc.yaml
- deployment.yaml

labels:
- pairs:
app.kubernetes.io/name: content
app.kubernetes.io/part-of: ipfs-workers

images:
# Pinned by digest in roles/content/defaults/main.yml (content_kubo_image,
# content_cluster_image), where a box can override them in host_vars: that
# is how one box runs a canary kubo while the others stay on the release.
- name: kubo
newName: {{ content_kubo_image.name }}
digest: {{ content_kubo_image.digest }}
- name: ipfs-cluster
newName: {{ content_cluster_image.name }}
digest: {{ content_cluster_image.digest }}

# The content-cluster Secret (cluster secret, peer identity, peer lists) is
# deliberately NOT here: it is created by roles/content from ansible-vault.
12 changes: 12 additions & 0 deletions roles/bootstrap/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ bootstrap_namespace: bootstrap
# libp2p swarm port (TCP, and UDP for QUIC / WebTransport / WebRTC-direct).
bootstrap_swarm_port: 4001

# The kubo image (k8s/bootstrap/kustomization.yaml.j2): this default, or the
# instance's own kubo_image ({name, digest}) from bootstrap_extra_instances.
#
# ipfs/kubo v0.43.1 (published 2026-09-15 00:52 UTC), multi-arch index, pinned
# by digest. Same image as content (roles/content/defaults/main.yml). Shipyard
# stops maintaining kubo on 2026-09-30: upgrades are deliberate, and go-libp2p
# / kubo security advisories need watching.
bootstrap_default_kubo_image:
name: ipfs/kubo
digest: sha256:b293923d66e490e70ced64df42ea7a6cf7eac2740e3fb29101df18070fa7be48
bootstrap_kubo_image: "{{ bootstrap_default_kubo_image }}"

# Loopback-only RPC API (probes, metrics, `ipfs` CLI via kubectl exec).
bootstrap_api_port: 5011
bootstrap_api: "/ip4/127.0.0.1/tcp/{{ bootstrap_api_port }}"
Expand Down
1 change: 1 addition & 0 deletions roles/bootstrap/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
bootstrap_wss_port: "{{ bs.wss_port }}"
bootstrap_wss_admin_port: "{{ bs.wss_admin_port }}"
bootstrap_kubo_uid: "{{ bs.uid }}"
bootstrap_kubo_image: "{{ bs.kubo_image | default(bootstrap_default_kubo_image) }}"
bootstrap_instance_peer_id: "{{ bs.peer_id }}"
# vault_bootstrap_privkey, vault_bootstrap_b_privkey, ... Looked up by
# name so a missing one is reported by the identity preflight, not here.
Expand Down
16 changes: 16 additions & 0 deletions roles/content/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ content_cluster_api_port: 9094 # loopback (REST API)
content_cluster_swarm_port: 9096 # TCP, the other boxes only
content_pinsvc_port: 9097 # loopback (Pinning Service API, behind Envoy)

# Images, pinned by digest (k8s/content/kustomization.yaml.j2). A box may set
# its own in host_vars to run a canary; scripts/recover-upstream-pinset.sh
# always uses these defaults.
#
# ipfs/kubo v0.43.1 (published 2026-09-15 00:52 UTC, the current v0.43.x;
# checked 2026-09-15), multi-arch index. Same image as k8s/bootstrap.
content_kubo_image:
name: ipfs/kubo
digest: sha256:b293923d66e490e70ced64df42ea7a6cf7eac2740e3fb29101df18070fa7be48
# ipfs/ipfs-cluster v1.1.6 (published 2026-05-11, the latest release; checked
# 2026-09-15), multi-arch index. The project publishes to Docker Hub as
# ipfs/ipfs-cluster.
content_cluster_image:
name: ipfs/ipfs-cluster
digest: sha256:a83266c524f1c0bc81d14fe3c8b46c5b83a7b2d8432fb8a50300f27d3c863dcd

# ---------------------------------------------------------------------------
# Remote pinning: ipfs-cluster's Pinning Service API (the API `ipfs pin remote`
# speaks), served over TLS by Envoy (k8s/content-pin) on every box under one
Expand Down
8 changes: 4 additions & 4 deletions scripts/recover-upstream-pinset.sh
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ capture_listing() {
exit 2
fi

# The same kubo and ipfs-cluster images the content cluster runs, by digest.
# The kubo and ipfs-cluster images the content cluster runs by default, by
# digest (a box's canary override in host_vars is not used here).
local images kubo_image cluster_image
images=$(python3 - <<'PY'
import yaml
k = yaml.safe_load(open("k8s/content/kustomization.yaml"))
imgs = {i["name"]: f'{i["newName"]}@{i["digest"]}' for i in k["images"]}
print(imgs["kubo"], imgs["ipfs-cluster"])
d = yaml.safe_load(open("roles/content/defaults/main.yml"))
print(*(f'{d[k]["name"]}@{d[k]["digest"]}' for k in ("content_kubo_image", "content_cluster_image")))
PY
)
read -r kubo_image cluster_image <<<"$images"
Expand Down
Loading