Merge: Gitea replaces GitLab + cockpit registry to Scaleway (Phase 2B)
Gitea (chart + existing postgres) is the git host behind git.fxhnt.ai (tailnet proxy, SSH :22); both repos migrated (foxhunt archived); cockpit image -> Scaleway Container Registry; build clones Gitea; Gitea webhook -> Argo auto-deploy. GitLab now idle (removed in 2C). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -130,8 +130,8 @@ gitea:
|
||||
ROOT_URL: https://git.fxhnt.ai/
|
||||
DOMAIN: git.fxhnt.ai
|
||||
SSH_DOMAIN: git.fxhnt.ai
|
||||
SSH_PORT: "22" # advertise clean git@git.fxhnt.ai in NEW clone URLs; legacy :2222 still
|
||||
# works via the proxy (Task 5). Port 22 is free — nothing host-SSHes the git node.
|
||||
SSH_PORT: "22" # clean git@git.fxhnt.ai clone URLs. Port 22 is free (nothing host-SSHes
|
||||
# the git node); :2222 retired, local remotes updated in Task 5 Step 2b.
|
||||
DISABLE_SSH: "false"
|
||||
database:
|
||||
DB_TYPE: postgres
|
||||
@@ -297,28 +297,26 @@ to:
|
||||
Delete the entire `listen 5050 ssl; server_name git.fxhnt.ai;` registry block (Scaleway registry is
|
||||
external — not proxied).
|
||||
|
||||
- [ ] **Step 2: Repoint the socat SSH proxy → Gitea SSH, on BOTH `:22` and `:2222`**
|
||||
- [ ] **Step 2: Repoint the socat SSH proxy to Gitea SSH on `:22` (drop `:2222`)**
|
||||
|
||||
Nothing ever SSHes into the git node itself, so port `22` is free for git-SSH. Expose Gitea SSH on both
|
||||
the standard `:22` (clean `git@git.fxhnt.ai` URLs) and the legacy `:2222` (existing remotes keep working —
|
||||
no churn). In the `ssh-proxy` container args, change the existing `:2222` target to Gitea:
|
||||
Nothing host-SSHes the git node, so use the standard port `22` and retire `:2222` entirely (clean
|
||||
`git@git.fxhnt.ai` URLs). In the `ssh-proxy` container args, change the listen port to `22` and the target
|
||||
to Gitea:
|
||||
```
|
||||
- "TCP-LISTEN:2222,fork,reuseaddr,sndbuf=1048576,rcvbuf=1048576"
|
||||
- "TCP:gitea-ssh.foxhunt.svc.cluster.local:22,sndbuf=1048576,rcvbuf=1048576"
|
||||
```
|
||||
Then add a SECOND socat container in the same pod for `:22` (duplicate the `ssh-proxy` container, rename
|
||||
`ssh-proxy-22`, listen on `22`, `containerPort: 22`):
|
||||
```yaml
|
||||
- name: ssh-proxy-22
|
||||
image: alpine/socat:latest
|
||||
args:
|
||||
- "TCP-LISTEN:22,fork,reuseaddr,sndbuf=1048576,rcvbuf=1048576"
|
||||
- "TCP:gitea-ssh.foxhunt.svc.cluster.local:22,sndbuf=1048576,rcvbuf=1048576"
|
||||
ports:
|
||||
- containerPort: 22
|
||||
```
|
||||
Ensure the Tailscale node/proxy advertises both ports `22` and `2222` (the tailnet sidecar's exposed
|
||||
ports / `serve` config — add `22` alongside the existing `2222`).
|
||||
Update the container `ports:` entry from `containerPort: 2222` → `containerPort: 22`. Ensure the Tailscale
|
||||
node/proxy advertises port `22` (update the tailnet sidecar's exposed ports / `serve` config: `22`,
|
||||
replacing `2222`).
|
||||
|
||||
- [ ] **Step 2b: Update local git remotes from `:2222` → default (port 22)**
|
||||
```bash
|
||||
cd /home/jgrusewski/Work/foxhunt && git remote set-url origin ssh://git@git.fxhnt.ai/gitadmin/foxhunt.git
|
||||
cd /home/jgrusewski/Work/fxhnt && git remote set-url origin ssh://git@git.fxhnt.ai/gitadmin/fxhnt.git
|
||||
cd /home/jgrusewski/Work/foxhunt && git remote -v | grep fetch
|
||||
```
|
||||
Expected: remotes now show `ssh://git@git.fxhnt.ai/...` (no `:2222`).
|
||||
|
||||
- [ ] **Step 3: Apply + restart the proxy**
|
||||
```bash
|
||||
@@ -332,11 +330,10 @@ Expected: rollout complete.
|
||||
- [ ] **Step 4: GATE — verify `git.fxhnt.ai` serves Gitea**
|
||||
```bash
|
||||
curl -sk https://git.fxhnt.ai/api/healthz | head -c 200; echo
|
||||
echo "--- SSH on :2222 (legacy remotes) ---"; git ls-remote ssh://git@git.fxhnt.ai:2222/gitadmin/fxhnt.git HEAD 2>&1 | head -1
|
||||
echo "--- SSH on :22 (clean URLs) ---"; git ls-remote ssh://git@git.fxhnt.ai/gitadmin/fxhnt.git HEAD 2>&1 | head -1
|
||||
echo "--- SSH on :22 (git@git.fxhnt.ai) ---"; git ls-remote ssh://git@git.fxhnt.ai/gitadmin/fxhnt.git HEAD 2>&1 | head -1
|
||||
```
|
||||
Expected: Gitea healthz JSON; BOTH ssh ls-remotes (`:2222` and `:22`) return the HEAD sha (proves Gitea
|
||||
web + SSH on both ports on the canonical name). **STOP + rollback (revert this file, re-apply) if any fail.**
|
||||
Expected: Gitea healthz JSON; the `:22` ssh ls-remote returns the HEAD sha (proves Gitea web + SSH on the
|
||||
canonical name). **STOP + rollback (revert this file, re-apply) if either fails.**
|
||||
|
||||
- [ ] **Step 5: Commit (foxhunt repo)**
|
||||
```bash
|
||||
|
||||
@@ -24,9 +24,9 @@ breaking the live cockpit deploy.
|
||||
via `git push --mirror` from existing local clones.
|
||||
- **Canonical hostname stays `git.fxhnt.ai`** (no permanent `gitea.fxhnt.ai`, no remote-URL churn).
|
||||
Gitea comes up internal-only; validate over a port-forward; then cut `git.fxhnt.ai` (HTTPS) + SSH over
|
||||
to Gitea in one switch. **SSH exposed on BOTH `:22` and `:2222`** — nothing host-SSHes the git node so
|
||||
`:22` is free; Gitea advertises the clean `git@git.fxhnt.ai` (`:22`) in new clone URLs while existing
|
||||
`:2222` remotes keep working (no churn). GitLab keeps running (unaddressed) as the 2C-removal fallback.
|
||||
to Gitea in one switch. **SSH on `:22`** (nothing host-SSHes the git node, so the standard port is free);
|
||||
clone URLs become the clean `git@git.fxhnt.ai` and `:2222` is retired (local remotes updated once).
|
||||
GitLab keeps running (unaddressed) as the 2C-removal fallback.
|
||||
- **Container registry:** cockpit image → **Scaleway Container Registry** (`rg.fr-par.scw.cloud/bizworx/`,
|
||||
namespace exists). Retire the in-cluster GitLab registry. External/managed, no registry pod.
|
||||
- **Argo integration:** Gitea push webhook → Argo Events webhook eventsource → sensor → submit
|
||||
@@ -44,8 +44,8 @@ breaking the live cockpit deploy.
|
||||
3. **Exposure:**
|
||||
- HTTPS: extend the nginx `*.fxhnt.ai` proxy (`infra/k8s/gitlab/tailscale-proxy.yaml`) — at cutover,
|
||||
repoint the `git.fxhnt.ai` server block `proxy_pass` → `gitea-http.foxhunt.svc:3000`.
|
||||
- SSH: expose Gitea SSH on BOTH `:22` and `:2222` via the Tailscale proxy (two socat listeners) at
|
||||
cutover; advertise `:22` in clone URLs, keep `:2222` for existing remotes.
|
||||
- SSH: expose Gitea SSH on `:22` via the Tailscale proxy (socat) at cutover; retire `:2222`; update the
|
||||
two local remotes to `ssh://git@git.fxhnt.ai/...`.
|
||||
- Registry `:5050` server block: removed (Scaleway registry is external, not proxied here).
|
||||
4. **Registry migration:**
|
||||
- `fxhnt/infra/argo/cockpit-build-deploy.yaml`: kaniko `--destination` + `--cache-repo` →
|
||||
|
||||
56
infra/k8s/argo/events/gitea-deploy-sensor.yaml
Normal file
56
infra/k8s/argo/events/gitea-deploy-sensor.yaml
Normal file
@@ -0,0 +1,56 @@
|
||||
# On push to fxhnt main/master in Gitea, submit the fxhnt-cockpit build+deploy workflow (Phase 2B).
|
||||
# Gitea push payload: { "ref": "refs/heads/main", "after": "<new-sha>", ... }
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Sensor
|
||||
metadata:
|
||||
name: gitea-deploy
|
||||
namespace: foxhunt
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-deploy
|
||||
app.kubernetes.io/part-of: foxhunt
|
||||
spec:
|
||||
template:
|
||||
# pod intentionally NOT part-of:foxhunt (avoids default-deny-all; matches working sensors)
|
||||
serviceAccountName: argo-workflow
|
||||
nodeSelector:
|
||||
k8s.scaleway.com/pool-name: platform
|
||||
dependencies:
|
||||
- name: gitea-push-dep
|
||||
eventSourceName: gitea-push
|
||||
eventName: push
|
||||
filters:
|
||||
data:
|
||||
- path: body.ref
|
||||
type: string
|
||||
value:
|
||||
- "refs/heads/main"
|
||||
- "refs/heads/master"
|
||||
triggers:
|
||||
- template:
|
||||
name: deploy-cockpit
|
||||
conditions: gitea-push-dep
|
||||
argoWorkflow:
|
||||
operation: submit
|
||||
source:
|
||||
resource:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Workflow
|
||||
metadata:
|
||||
generateName: fxhnt-cockpit-
|
||||
namespace: foxhunt
|
||||
spec:
|
||||
serviceAccountName: argo-workflow
|
||||
podGC:
|
||||
strategy: OnPodCompletion
|
||||
ttlStrategy:
|
||||
secondsAfterCompletion: 3600
|
||||
workflowTemplateRef:
|
||||
name: fxhnt-cockpit
|
||||
arguments:
|
||||
parameters:
|
||||
- name: commit-sha
|
||||
parameters:
|
||||
- src:
|
||||
dependencyName: gitea-push-dep
|
||||
dataKey: body.after
|
||||
dest: spec.arguments.parameters.0.value
|
||||
28
infra/k8s/argo/events/gitea-push-eventsource.yaml
Normal file
28
infra/k8s/argo/events/gitea-push-eventsource.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
# Gitea push webhook → Argo Events. Replaces the old gitlab-push eventsource (Phase 2B).
|
||||
# Gitea posts to gitea-push-eventsource-svc:12000/push on push to the fxhnt repo.
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: EventSource
|
||||
metadata:
|
||||
name: gitea-push
|
||||
namespace: foxhunt
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-push
|
||||
app.kubernetes.io/part-of: foxhunt
|
||||
spec:
|
||||
template:
|
||||
# NOTE: pod is intentionally NOT part-of:foxhunt — that label triggers default-deny-all. The working
|
||||
# workflow-trigger/gitlab-push eventsource pods have no part-of, so they stay default-allow.
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-push
|
||||
nodeSelector:
|
||||
k8s.scaleway.com/pool-name: platform
|
||||
service:
|
||||
ports:
|
||||
- port: 12000
|
||||
targetPort: 12000
|
||||
webhook:
|
||||
push:
|
||||
port: "12000"
|
||||
endpoint: /push
|
||||
method: POST
|
||||
40
infra/k8s/gitea/clusterip-services.yaml
Normal file
40
infra/k8s/gitea/clusterip-services.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
# The gitea chart's gitea-http/gitea-ssh services are HEADLESS (clusterIP: None), so they resolve to the
|
||||
# pod IP (100.64.x.x). That range OVERLAPS the Tailscale CGNAT range (100.64.0.0/10), so the tailscale
|
||||
# sidecar in the tailscale-gitlab-proxy pod swallows traffic to the pod IP. These normal ClusterIP services
|
||||
# give Gitea a service IP in the service CIDR (10.32.x.x, outside the tailscale range) — the proxy nginx +
|
||||
# socat target these instead. (GitLab worked because its webservice svc was a normal ClusterIP.)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-web
|
||||
namespace: foxhunt
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/instance: gitea
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-sshd
|
||||
namespace: foxhunt
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/instance: gitea
|
||||
ports:
|
||||
- name: ssh
|
||||
port: 22
|
||||
targetPort: 2222 # rootless gitea listens on 2222 internally (can't bind privileged 22)
|
||||
protocol: TCP
|
||||
58
infra/k8s/gitea/networkpolicy.yaml
Normal file
58
infra/k8s/gitea/networkpolicy.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
# Gitea NetworkPolicy (foxhunt ns has default-deny-all). Egress: postgres + DNS + in-cluster webhook
|
||||
# target + general HTTPS. Ingress: from platform/argo pods + the tailscale proxy → :3000 (web) and :22 (ssh).
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: foxhunt
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: gitea
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# web (3000) + ssh (22) from platform + argo-workflow pods (cockpit build clones over HTTP)
|
||||
- from:
|
||||
- podSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/part-of
|
||||
operator: In
|
||||
values: ["foxhunt", "argo-workflows"]
|
||||
ports:
|
||||
- { port: 3000, protocol: TCP }
|
||||
- { port: 2222, protocol: TCP }
|
||||
# web + ssh from the tailscale proxy (nginx + socat) that fronts git.fxhnt.ai
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: tailscale-gitlab-proxy
|
||||
ports:
|
||||
- { port: 3000, protocol: TCP }
|
||||
- { port: 2222, protocol: TCP }
|
||||
egress:
|
||||
# PostgreSQL
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: postgres
|
||||
ports:
|
||||
- { port: 5432, protocol: TCP }
|
||||
# DNS
|
||||
- ports:
|
||||
- { port: 53, protocol: UDP }
|
||||
- { port: 53, protocol: TCP }
|
||||
# Argo Events webhook target (gitea push hook → gitea-push eventsource :12000). The eventsource pod is
|
||||
# not part-of:foxhunt (stays default-allow), so allow egress to any in-namespace pod on 12000.
|
||||
- to:
|
||||
- podSelector: {}
|
||||
ports:
|
||||
- { port: 12000, protocol: TCP }
|
||||
# general HTTPS (avatars, external clones) — external only, exclude cluster CIDRs
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except: ["10.32.0.0/16", "172.16.0.0/16"]
|
||||
ports:
|
||||
- { port: 443, protocol: TCP }
|
||||
73
infra/k8s/gitea/values.yaml
Normal file
73
infra/k8s/gitea/values.yaml
Normal file
@@ -0,0 +1,73 @@
|
||||
# Gitea — lightweight git host replacing GitLab (Phase 2B). External Postgres (existing in-cluster
|
||||
# `postgres`), no bundled DB/redis/memcached, Actions off (Argo does CI). Internal-only until cutover.
|
||||
replicaCount: 1
|
||||
image:
|
||||
rootless: true
|
||||
|
||||
# RWO PVC (sbs-default-retain) → only one pod can mount it. RollingUpdate deadlocks (new pod can't
|
||||
# attach while old holds it). Recreate terminates old before starting new.
|
||||
strategy:
|
||||
type: Recreate
|
||||
|
||||
# Disable all bundled subcharts — reuse the existing in-cluster postgres, no redis/memcached.
|
||||
postgresql:
|
||||
enabled: false
|
||||
postgresql-ha:
|
||||
enabled: false
|
||||
redis-cluster:
|
||||
enabled: false
|
||||
redis:
|
||||
enabled: false
|
||||
# chart 12.x replaced redis with valkey — disable both, gitea uses embedded queue/cache/session
|
||||
valkey-cluster:
|
||||
enabled: false
|
||||
valkey:
|
||||
enabled: false
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 5Gi
|
||||
storageClass: sbs-default-retain
|
||||
|
||||
resources:
|
||||
requests: { cpu: 100m, memory: 256Mi }
|
||||
limits: { cpu: "1", memory: 2Gi } # 2Gi headroom: indexing the 876MB foxhunt pack OOMed at 512Mi
|
||||
|
||||
service:
|
||||
http: { type: ClusterIP, port: 3000 }
|
||||
ssh: { type: ClusterIP, port: 22 }
|
||||
|
||||
gitea:
|
||||
admin:
|
||||
existingSecret: gitea-admin
|
||||
config:
|
||||
actions:
|
||||
ENABLED: "false" # Argo does CI/CD; Gitea Actions off (subchart removed in chart 12.x)
|
||||
server:
|
||||
ROOT_URL: https://git.fxhnt.ai/
|
||||
DOMAIN: git.fxhnt.ai
|
||||
SSH_DOMAIN: git.fxhnt.ai
|
||||
SSH_PORT: "22" # clean git@git.fxhnt.ai clone URLs; :2222 retired (Task 5).
|
||||
DISABLE_SSH: "false"
|
||||
database:
|
||||
DB_TYPE: postgres
|
||||
HOST: postgres.foxhunt.svc.cluster.local:5432
|
||||
NAME: gitea
|
||||
USER: gitea
|
||||
service:
|
||||
DISABLE_REGISTRATION: "true"
|
||||
webhook:
|
||||
# allow delivery to in-cluster targets (Argo Events eventsource on the 10.32.x service CIDR);
|
||||
# default blocks private hosts. Argo auto-deploy webhook needs this.
|
||||
ALLOWED_HOST_LIST: "private"
|
||||
# No redis/memcached — use embedded adapters
|
||||
cache:
|
||||
ADAPTER: memory
|
||||
session:
|
||||
PROVIDER: db
|
||||
queue:
|
||||
TYPE: level
|
||||
additionalConfigFromEnvs:
|
||||
- name: GITEA__database__PASSWD
|
||||
valueFrom:
|
||||
secretKeyRef: { name: gitea-db, key: password }
|
||||
@@ -75,10 +75,10 @@ spec:
|
||||
- name: ssh-proxy
|
||||
image: alpine/socat:latest
|
||||
args:
|
||||
- "TCP-LISTEN:2222,fork,reuseaddr,sndbuf=1048576,rcvbuf=1048576"
|
||||
- "TCP:gitlab-gitlab-shell.foxhunt.svc.cluster.local:2222,sndbuf=1048576,rcvbuf=1048576"
|
||||
- "TCP-LISTEN:22,fork,reuseaddr,sndbuf=1048576,rcvbuf=1048576"
|
||||
- "TCP:gitea-sshd.foxhunt.svc.cluster.local:22,sndbuf=1048576,rcvbuf=1048576"
|
||||
ports:
|
||||
- containerPort: 2222
|
||||
- containerPort: 22
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
@@ -152,7 +152,7 @@ data:
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# GitLab — git.fxhnt.ai
|
||||
# Gitea — git.fxhnt.ai (replaced GitLab, Phase 2B cutover)
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name git.fxhnt.ai;
|
||||
@@ -164,7 +164,7 @@ data:
|
||||
client_max_body_size 0;
|
||||
|
||||
location / {
|
||||
proxy_pass http://gitlab-webservice-default.foxhunt.svc.cluster.local:8181;
|
||||
proxy_pass http://gitea-web.foxhunt.svc.cluster.local:3000;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Postgres: accepts connections from foxhunt app pods, GitLab, and Grafana
|
||||
# Postgres: accepts connections from foxhunt app pods, GitLab, Grafana, and Gitea
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
@@ -23,6 +23,9 @@ spec:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: grafana
|
||||
- podSelector: # Gitea (Phase 2B) reuses the in-cluster postgres
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: gitea
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
|
||||
@@ -8,6 +8,7 @@ terraform {
|
||||
|
||||
inputs = {
|
||||
dns_zone = "fxhnt.ai"
|
||||
# Tailscale IP of foxhunt-gitlab proxy pod
|
||||
git_ip = "100.90.76.85"
|
||||
# Tailscale IP of the foxhunt-gitlab proxy pod (live node foxhunt-gitlab; the old 100.90.76.85
|
||||
# was a stale prior IP — its duplicate A records across *.fxhnt.ai were removed 2026-06-21).
|
||||
git_ip = "100.95.225.27"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user