Files
homelab/kubernetes/apps/gitea/statefulset.yaml
claude-botandClaude Opus 5.5 7ada3540b5
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
chore(paperclip): remove Paperclip and everything that only served it
Removes the Paperclip deployment (namespace paperclip, CNPG cluster
pclp-pg, ingresses, image automation, server image build) and the
infrastructure that existed only for its agents:

- agent sandbox: paperclip-renner namespace and CNPs, the
  kubernetes-sigs/agent-sandbox controller with its namespace, CNP and
  Renovate rules
- agent-runtime-{go,ops} images and the build-agent-runtime pipeline
- matrix bridge (Element <-> Paperclip agents) and synapse's appservice
  registration mount
- monitoring loki-read-gateway (only called by the paperclip Role)
- MQTT account agents-read and the controller's RBAC in ns paperclip
- the OpenBao secret-exists-check policy file
- agent admits in the wiki, lidarr, shelly-manager, mosquitto and
  hubble-relay CNPs; the paperclip-api Gitea webhook host; the wiki API
  key; the ClusterSecretStore namespace entry; the pclp-pg RECOVERY row
- the Paperclip design spec and plan

Authentik group "Paperclip Users" is switched to state: absent so the
blueprint deletes it. package-retention's EXCLUDE_PACKAGES becomes
optional, since its only value was the agent-runtime prefix.

The shelly-manager api-proxy sidecar stays: mqtt-account-controller
calls shelly-manager-api too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 07:50:12 +02:00

171 lines
8.2 KiB
YAML

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: gitea
namespace: gitea
labels:
app.kubernetes.io/name: gitea
spec:
serviceName: gitea
replicas: 1 # SQLite => single writer. Do NOT scale up without moving to Postgres first.
selector:
matchLabels:
app.kubernetes.io/name: gitea
template:
metadata:
labels:
app.kubernetes.io/name: gitea
spec:
# The migrated data + app.ini live on the PVC and are owned by uid/gid 1000
# (the image's `git` user). fsGroup keeps that true for mounted volumes.
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: gitea
# Rootless image: runs as uid/gid 1000 (username `git`), defaults
# GITEA_WORK_DIR=/var/lib/gitea and GITEA_CUSTOM=/var/lib/gitea/custom,
# alpine base (tar for the data load), and its entrypoint runs
# environment-to-ini so the GITEA__* overrides below apply. Do NOT
# override the entrypoint (that skips environment-to-ini AND trips the
# RUN_USER check -> fatal). The migrated /var/lib/gitea/data drops in as-is,
# but the LXC's /etc/gitea/app.ini is RELOCATED to custom/conf/app.ini
# (GITEA_APP_INI below) and its RUN_USER must read `git`, not `gitea` —
# both handled as explicit steps in MIGRATION-gitea-woodpecker.md. No
# imagepolicy marker: a minor bump migrates the live SQLite database and
# needs a snapshot first (volumesnapshot-pre-upgrade.yaml). 1.21.4 ->
# 1.27.3 in REN-1367; the
# next step, 28.x, changes the outgoing-request (webhook) host lists.
image: gitea/gitea:1.27.3-rootless@sha256:1c17ecaead42eb3b5391553d8708103a4beb0e86edf5b9ebc1eb269c318845f2
env:
- name: GITEA_WORK_DIR
value: /var/lib/gitea
- name: GITEA_CUSTOM
value: /var/lib/gitea/custom
- name: GITEA_APP_INI
value: /var/lib/gitea/custom/conf/app.ini
# Native LXC installs commonly log to /var/log/gitea, which is
# root-owned image filesystem in the container -> uid 1000 can't
# mkdir it and Gitea dies at logger init. Force logs onto the PVC.
# env overrides whatever [log] ROOT_PATH the migrated app.ini carries.
- name: GITEA__log__ROOT_PATH
value: /var/lib/gitea/log
# SSH: use Gitea's built-in Go SSH server on 2222 (the gitea-ssh LB
# maps 22 -> 2222). Env overrides the migrated app.ini, so we don't
# edit the copied config.
- name: GITEA__server__START_SSH_SERVER
value: "true"
- name: GITEA__server__SSH_LISTEN_PORT
value: "2222"
- name: GITEA__server__SSH_PORT
value: "22"
- name: GITEA__server__SSH_DOMAIN
value: gitea.renner.uno
# The LXC ran RUN_USER=gitea, so every existing remote/clone URL is
# gitea@gitea.renner.uno. The rootless image runs as `git`, so the
# built-in SSH server would only accept `git@` and reject `gitea@`.
# BUILTIN_SSH_SERVER_USER is what the built-in server checks the login
# name against (defaults to RUN_USER=git) -> set it to `gitea` so
# gitea@ authenticates. SSH_USER only sets the DISPLAYED clone URL (it
# does NOT affect auth) -> also gitea so the UI matches. This keeps all
# existing gitea@ remotes working with no client changes. Trade-off:
# git@ no longer authenticates (single built-in login), which is fine —
# nothing here uses git@.
- name: GITEA__server__BUILTIN_SSH_SERVER_USER
value: gitea
- name: GITEA__server__SSH_USER
value: gitea
- name: GITEA__server__DISABLE_SSH
value: "false"
# Reuse the LXC's OpenSSH host keys (copied to data/ssh/ during the
# migration) so existing clients don't get "REMOTE HOST IDENTIFICATION
# HAS CHANGED". Paths are relative to APP_DATA_PATH (/var/lib/gitea/data).
- name: GITEA__server__SSH_SERVER_HOST_KEYS
value: "ssh/ssh_host_ed25519_key,ssh/ssh_host_rsa_key"
# Gitea Actions was decommissioned — keep it off.
- name: GITEA__actions__ENABLED
value: "false"
# Package-registry GC cadence (#336). The container registry orphans
# a whole image-layer set every time a tag is overwritten, and the
# ci-* images + shelly-manager (cron + push builds) rebuild often. At
# the default @midnight / OLDER_THAN=24h, a day's worth of orphaned
# blobs (~10G) piled up between runs and filled the volume. Run the
# GC every 6h with a 4h age cutoff so orphans are reclaimed same-day.
# 4h is far beyond any in-flight push, so a live upload is never GC'd.
# (Section name's dot is escaped as _0X2E_ for environment-to-ini;
# verified it renders [cron.cleanup_packages] correctly.)
- name: GITEA__cron_0X2E_cleanup_packages__SCHEDULE
value: "@every 6h"
- name: GITEA__cron_0X2E_cleanup_packages__OLDER_THAN
value: "4h"
# LFS storage path. Gitea deprecated [server] LFS_CONTENT_PATH in
# favour of [lfs] PATH (removal warning shows in the admin dashboard).
# Unlike the pure overrides above, env-to-ini can only ADD keys, not
# remove them, so the stale [server] LFS_CONTENT_PATH had to be deleted
# from the on-PVC app.ini by hand as part of this change; this env var
# is the tracked source for the replacement key. Same path value, so
# existing LFS objects under data/lfs are untouched.
- name: GITEA__lfs__PATH
value: /var/lib/gitea/data/lfs
# Disable query-string (?token=) API auth. Recommended by Gitea and the
# default from 1.23; clears the second startup notice on the dashboard.
# Nothing here authenticates via query tokens (CI uses webhooks/OAuth).
- name: GITEA__security__DISABLE_QUERY_AUTH_TOKEN
value: "true"
# Webhook targets Gitea may call; every configured webhook host.
- name: GITEA__security__ALLOWED_HOST_LIST
value: "ci.renner.uno,wiki.ai.svc.cluster.local,review-bot.review-bot.svc.cluster.local"
ports:
- name: http
containerPort: 3000
- name: ssh
containerPort: 2222
# The first start on a new minor version runs the database migrations
# before the HTTP server listens. Give that up to 15 minutes; without
# it the liveness probe kills Gitea in the middle of a migration.
startupProbe:
httpGet:
path: /api/healthz
port: http
periodSeconds: 10
failureThreshold: 90
readinessProbe:
httpGet:
path: /api/healthz
port: http
initialDelaySeconds: 10
periodSeconds: 10
livenessProbe:
httpGet:
path: /api/healthz
port: http
initialDelaySeconds: 30
periodSeconds: 30
failureThreshold: 5
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 1Gi
volumeMounts:
- name: data
mountPath: /var/lib/gitea
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ceph-block
resources:
# This template only applies when the claim does not exist yet. The
# live size of data-gitea-0 is set in pvc.yaml (REN-583), not here:
# volumeClaimTemplates is immutable on an existing StatefulSet, so a
# change to this value cannot be applied and Flux would reject the
# whole object. Leave it at 40Gi.
requests:
storage: 40Gi