Document staged Gitea migration to Atlas

This commit is contained in:
Fabio Scotto di Santolo
2026-10-01 21:10:32 +02:00
parent 802cb8c7ba
commit 5b0f415163
4 changed files with 104 additions and 0 deletions

View File

@@ -260,6 +260,13 @@ successfully. The first monthly scrub remains a runtime check.
### Priority 3 - Service expansion
- [ ] After data protection and recovery are validated, populate `/zpool/media/music` and validate Navidrome.
- [x] Design the staged Prometheus-to-Atlas Gitea migration in `docs/atlas-gitea-migration.md`.
The approved topology keeps NPM on Prometheus and moves HTTPS and public SSH (TCP/2222) together;
the existing rootful image/data layout is retained. No data has been moved or traffic changed.
- [ ] Prepare a separate Atlas Gitea dataset, disabled Quadlet, and isolated restore test from the
verified Prometheus backup; validate SQLite, repositories, SSH host keys, and target backups.
- [ ] After an explicit outage approval, perform the final consistent copy and HTTPS/SSH cutover,
then remove Gitea from Prometheus' desired stack and backup export without deleting source data.
- [ ] Design and deploy Nextcloud as another explicitly temporary Atlas service before Uranus. Give it
separate persistent application, database, and cache storage; keep credentials in Vault; publish it only
through NPM over the Prometheus--Aegis gateway; and define backup, upgrade, and eventual Uranus-migration

View File

@@ -322,6 +322,10 @@ alla LAN. Dopo la verifica dei servizi, configurare manualmente i Proxy Host NPM
negli `AllowedIPs`; aggiungere la VIP Uranus quando esisterà. Dopo il reload di firewalld, Ansible
ricarica le reti Podman rootful di Prometheus per conservare DNS e connettività del proxy.
La migrazione Gitea da Prometheus ad Atlas è pianificata, ma non ancora eseguita, in
[`docs/atlas-gitea-migration.md`](docs/atlas-gitea-migration.md). NPM resta su Prometheus;
stack sorgente e instradamento pubblico rimangono invariati fino a un cutover separato e validato.
Validare il gateway con:
```bash

View File

@@ -298,6 +298,10 @@ and Aegis (`10.0.0.2`). Their state is initialized ex novo in `/zpool/services/d
`/zpool/services/data/syncthing`; no source application state is migrated. The music library at
`/zpool/media/music` is populated separately.
The staged, not-yet-executed Gitea move from Prometheus to Atlas is described in
[`docs/atlas-gitea-migration.md`](docs/atlas-gitea-migration.md). NPM remains on Prometheus;
the source stack and public routes stay unchanged until a separately validated cutover.
The separate `wireguard_overlay` role manages `wg0` between Prometheus (`10.0.0.1`) and Aegis
(`10.0.0.2`), generating private keys once on their respective hosts and exchanging only public keys
through Ansible. Prometheus alone opens `51820/udp`. Aegis forwards only the declared overlay-to-LAN

View File

@@ -0,0 +1,89 @@
# Gitea migration from Prometheus to Atlas
This is a staged migration plan, not a cutover authorization. Keep the source
Gitea, its data, both NPM Proxy Hosts, and public DNS unchanged until the
target and rollback have been tested. Gitea is temporary on Atlas until
Uranus; NPM remains on Prometheus.
## Observed source and chosen topology (2026-10-01)
- Prometheus runs the rootful `docker.gitea.com/gitea:1.25.2` image in its
managed Compose stack. `/opt/gitea/data` is about 280 MiB, uses SQLite,
and contains 33 repositories. A live read-only SQLite `quick_check` passed.
`/home/git/.ssh` is a separate small bind mount; `/opt/gitea/data/ssh`
contains the existing SSH host keys. Neither tree may be discarded.
- Gitea answers HTTP 200 on Prometheus port 3000. NPM currently forwards
`git.fscotto.duckdns.org` and `git.ov-ad3410.infomaniak.ch` to the Compose
hostname `gitea:3000`. Public DNS resolves to Prometheus. The container's
SSH port is bound only to `127.0.0.1:222`; this is not a public Gitea SSH
listener. Prometheus' public port 22 remains administrative SSH.
- Atlas has a healthy pool and a verified, private Prometheus backup under
`/zpool/backup/hosts/prometheus/latest`. The 2026-10-01 scheduled export
and pull succeeded. The intended target is a separate
`/zpool/services/data/gitea` dataset, not `Archive` or the backup dataset.
- The approved cutover keeps NPM on Prometheus, changes the two HTTP Proxy
Hosts to Atlas over the Prometheus--Aegis gateway, and offers public Gitea
SSH on port 2222 via the same gateway. Prometheus port 22 is unchanged.
HTTPS and SSH must be validated together before declaring cutover.
- Preserve the same **rootful** Gitea image and `/data` layout at first. The
upstream rootless image uses different mount paths and SSH implementation;
changing image type during a data migration is not a drop-in operation.
Pin the same version initially; consider upgrades separately.
## Phase 1: prepare without traffic changes
1. Provision a dedicated target dataset and non-login service identity via
Ansible, keeping UID/GID distinct from Atlas' reserved Immich `1100`.
Install a rootful Quadlet but do not start it or open firewall ports yet.
2. Verify the selected Atlas backup SHA-256 and metadata, then extract **only**
`opt/gitea/data` and `home/git/.ssh` to private staging. Never unpack NPM,
WireGuard, or other host configuration from this sensitive tarball into a
live namespace. Preserve Gitea's existing SSH host keys; adjust ownership
to the declared Atlas service UID/GID and apply only path-scoped SELinux
labels needed by the container.
3. Validate SQLite integrity, repository count and representative `git fsck`,
LFS/attachment presence, permissions, and a test container with no
production ingress or outbound network. Because the source stays active,
this is a rehearsal copy, not the final cutover copy. Regenerate Git hooks
if the changed installation path requires it, as documented by Gitea.
4. Confirm that Atlas snapshots, Borg, and offline USB include the new dataset;
test at least one independent restore before user traffic is accepted.
## Phase 2: explicit final cutover
1. Agree on an outage and record source/target versions, pool health, the
latest backups, SSH host-key fingerprints, and both current NPM routes.
Stop the Prometheus export timer for the change window so it cannot
restart the old Compose stack unexpectedly.
2. Quiesce source writes. Run one final consistent Prometheus export, pull it
to Atlas, verify checksum and timestamp, then stop the source Gitea. Keep
`/opt/gitea/data` and `/home/git/.ssh` intact for rollback. Do not allow
source Gitea to restart after accepting writes on Atlas.
3. Restore the final Gitea-only payload to the target and repeat integrity
checks. Set Gitea's advertised SSH port to 2222 while retaining its
existing HTTPS `ROOT_URL` and host keys. Start the pinned Atlas container,
initially without public ingress; validate local HTTP, SQLite, repositories,
LFS/attachments, and SSH host-key identity.
4. Permit only Aegis' source-NAT address to reach Atlas' Gitea HTTP and SSH
ports. Enable the public TCP/2222 forward on Prometheus to Atlas over Aegis
without changing administrative TCP/22. Update **both** NPM Proxy Hosts
from `gitea:3000` to Atlas' HTTP endpoint. Do not change public DNS.
5. Test HTTPS login, representative clone/push, LFS, and public SSH clone/push
on port 2222 from outside the Atlas LAN. Record the last source write and
first healthy target service times; do not claim RPO/RTO without measuring.
6. Only after successful traffic validation, remove Gitea from Prometheus'
desired Compose stack and its backup-export path/container checks, leaving
NPM and its backups operational. Do not delete the old data. Verify the
next Atlas snapshot/Borg run covers Gitea and test a restored target copy.
## Rollback gate
Before Atlas accepts writes, revert the two NPM routes, disable the public
2222 forward, and restart the unchanged source Gitea if target validation
fails. **After Atlas accepts writes, do not blindly restart the source:** its
SQLite database and repositories are stale. Quiesce Atlas, capture its new
data, and decide a reverse migration or an extended outage explicitly.
Upstream references: [rootful container layout](https://docs.gitea.com/1.25/installation/install-with-docker/),
[rootless incompatibility](https://docs.gitea.com/installation/install-with-docker-rootless/),
and [restore and hook regeneration](https://docs.gitea.com/1.26/administration/backup-and-restore/).