Compare commits

...

2 Commits

Author SHA1 Message Date
juvdiaz 84b60979f2 Update debian ip 2026-06-26 22:50:19 -06:00
juvdiaz 2f290b8ce2 Moving gitea to debian host 2026-06-26 22:16:10 -06:00
19 changed files with 67 additions and 68 deletions

View File

@ -16,12 +16,12 @@ jobs:
find . -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
git init
git remote add origin https://lab2025.duckdns.org/git/jv/my-homelab-configs.git
git remote add origin ssh://git@192.168.100.73:32222/jv/my-homelab-configs.git
git fetch --prune origin +refs/heads/main:refs/remotes/origin/main +refs/tags/*:refs/tags/*
git checkout --force "${{ gitea.sha }}"
git config --global --add safe.directory "$PWD"
- name: Block automatic deploy for Raspberry Pi Gitea changes
- name: Block automatic deploy for external Gitea changes
run: |
set -euo pipefail
@ -115,7 +115,7 @@ jobs:
if [[ -n "${blocked_files}" ]]; then
printf '%s\n' "${blocked_files}"
echo "Raspberry Pi Gitea service changes require a manual Debian run."
echo "External Gitea service changes require a manual Debian run."
exit 1
fi

View File

@ -142,8 +142,8 @@ cd ~/my-homelab-configs
./lab.sh up
```
The script first deploys external Gitea to the Raspberry Pi with Docker Compose
under `/data/homelab-gitea`, backed by the Raspberry Pi SSD, so Git stays
The script first deploys external Gitea to the Debian host with Docker Compose
under `/data/homelab-gitea`, backed by the HP laptop NVMe, so Git stays
outside the Kubernetes rebuild blast radius. It then detects the
Pimox host at `192.168.100.80` in auto mode. When SSH, `qm`, and `vmbr0` are
available, it applies `bootstrap/provisioning`, creates or reuses the Debian 13
@ -197,8 +197,8 @@ translation endpoints such as `save_idea.php`, `visitor_ideas.php`,
`translate.php`, and `save_lang.php`.
Set `LAB_GITEA_DEPLOY=false` to skip the external Gitea deployment step when the
Raspberry Pi service is already managed manually. The default Gitea target is
`jv@192.168.100.89`, install directory `/data/homelab-gitea`, HTTP port `3000`,
service is already managed manually. The default Gitea target is
`jv@192.168.100.73`, install directory `/data/homelab-gitea`, HTTP port `3000`,
and SSH port `32222`.
## Validation
@ -215,7 +215,7 @@ kubectl -n website-production get pods -o wide
kubectl -n demos-static get pods -o wide
kubectl -n heimdall get pods -o wide
ssh jv@192.168.100.89 'cd /data/homelab-gitea && sudo docker compose ps'
ssh jv@192.168.100.73 'cd /data/homelab-gitea && sudo docker compose ps'
docker info --format '{{.DockerRootDir}}'
df -h / /data /data/openebs/local /data/docker
@ -250,13 +250,12 @@ Run a full cluster rebuild from the Debian server with:
./lab.sh rebuild-cluster
```
That path preserves external Raspberry Pi Gitea, rebuilds the Pimox template
That path preserves external Gitea, rebuilds the Pimox template
with 2 cores and 4 GiB memory, replaces two Pimox worker VMs with 2 cores and
4 GiB memory, and joins those workers to the Kubernetes cluster. CPU affinity is
disabled by default because the Bullseye-pinned Pimox `qm` does not support it.
The Raspberry Pi is still included as a Kubernetes worker by default; `nuke`
does not clean it unless you explicitly add it to `WORKER_SSH_TARGETS`, so the
external Gitea Docker service survives cluster rebuilds.
does not clean it unless you explicitly add it to `WORKER_SSH_TARGETS`.
To exclude the Raspberry Pi from the Kubernetes cluster, set
`LAB_INCLUDE_RASPBERRY_WORKER=false`. To manage workers manually instead, add
@ -287,7 +286,7 @@ duplicate those PV manifests when you want storage on another node.
`homelab.dev/workload-class=control-plane` on the Debian control plane
- `homelab.dev/node-role=edge-app`, `homelab.dev/storage=local`, and
`homelab.dev/workload-class=edge` on the Raspberry Pi worker
- `homelab.dev/node-role=app`, `homelab.dev/storage=nvme`, and
- `homelab.dev/node-role=app`, `homelab.dev/storage=ssd`, and
`homelab.dev/workload-class=platform` on automated Pimox worker clones when
those workers are enabled
@ -390,8 +389,8 @@ are clean, individual policies can be promoted to `Enforce` in
`apps/supply-chain-policy` adds a separate Kyverno `ImageValidatingPolicy` for
the images built by this repo and pushed to the local registry. The policy
targets `192.168.100.68:30500/php-website:*` and
`192.168.100.68:30500/demos-static:*`, mutates admitted pods to image digests,
targets `192.168.100.73:30500/php-website:*` and
`192.168.100.73:30500/demos-static:*`, mutates admitted pods to image digests,
and audits whether the image has both:
- a valid Cosign signature from the homelab signing key
@ -513,7 +512,7 @@ than a `/heimdall/` path.
The `n8n` app runs in the `n8n` namespace with retained OpenEBS storage and is
exposed at `https://n8n.lab2025.duckdns.org`. It receives
`OLLAMA_BASE_URL=http://192.168.100.68:11434` so workflows can call the existing
`OLLAMA_BASE_URL=http://192.168.100.73:11434` so workflows can call the existing
Debian-host Ollama API for translation prewarming and batch jobs.
The `arr-stack` app runs Prowlarr, Sonarr, Radarr, qBittorrent, Kapowarr,
@ -539,14 +538,14 @@ Buildx state, and image caches from filling `/`.
## Gitea
Gitea is external bootstrap infrastructure. It runs on the Raspberry Pi as an
Gitea is external bootstrap infrastructure. It runs on the Debian host as an
always-on Docker Compose service from `infra/gitea/docker-compose.yml`, not as a
Kubernetes workload. This keeps Git available when the Kubernetes cluster is
destroyed and rebuilt.
The default data path is `/data/homelab-gitea/data` on the Raspberry Pi SSD.
The Raspberry Pi Docker root is also expected to live on the SSD-backed `/data`
mount rather than the SD card.
The default data path is `/data/homelab-gitea/data` on the HP laptop NVMe. The
Docker root is also expected to live on the `/data` storage path rather than the
root filesystem.
Public source browsing stays available through
`https://lab2025.duckdns.org/git/`. Registration is disabled and anonymous users
@ -578,16 +577,16 @@ Deploy or refresh the external Gitea container from the Debian host with:
## Gitea Backups
`./lab.sh up` installs a Debian-host systemd timer named
`homelab-gitea-backup.timer`. The timer runs daily, SSHes to the Raspberry Pi,
executes `gitea dump` inside the Gitea Docker container, copies the dump back to
Debian, and stores it under `/home/jv/backups/gitea`. The default retention is
30 days.
`homelab-gitea-backup.timer`. The timer runs daily, SSHes to the configured
Gitea host, executes `gitea dump` inside the Gitea Docker container, copies the
dump back to Debian, and stores it under `/home/jv/backups/gitea`. The default
retention is 30 days.
The same install step also creates `homelab-gitea-restore-drill.timer`. The
monthly drill is non-destructive: it verifies the latest backup ZIP, extracts it
to a temporary directory, records a report under
`/home/jv/backups/gitea-restore-drills`, and removes the temporary extract. It
does not write into the live Raspberry Pi Gitea data directory.
does not write into the live Gitea data directory.
Run a manual backup from the Debian server with:
@ -617,7 +616,7 @@ This repo includes a Gitea Actions workflow at
`.gitea/workflows/homelab-main.yml`. It runs only on pushes to `main` and targets
a repository-scoped Debian host runner with the label `homelab-debian`.
The workflow only blocks automatic deploy for Raspberry Pi Gitea service
The workflow only blocks automatic deploy for external Gitea service
changes: files under `infra/gitea/`, or edits inside the `deploy_gitea`,
`install_gitea_backup_timer`, `backup_gitea`, or `drill_gitea_restore`
functions in `lab.sh`. Other changes use `HOMELAB_ACTION_COMMAND=auto` by
@ -631,7 +630,7 @@ on the runner to force one path.
`./lab.sh bootstrap-gitea-repo` also registers the Debian host SSH public key
with the Gitea repository and switches the Debian working copy's `gitea` remote
to `ssh://git@192.168.100.89:32222/jv/my-homelab-configs.git`. The default key
to `ssh://git@192.168.100.73:32222/jv/my-homelab-configs.git`. The default key
is `/home/jv/.ssh/id_ed25519.pub`; set `LAB_GITEA_REPO_SSH_KEY_PATH` to use a
different Debian-host key, or `LAB_GITEA_REPO_SSH_BOOTSTRAP=false` to leave SSH
access unchanged. The Actions deploy job uses the checked-out Actions workspace
@ -684,8 +683,8 @@ links, iptables rules, and local OpenTofu state. It does not delete retained dat
under `/data/openebs/local`.
For multi-node labs, set `WORKER_SSH_TARGETS` to a space-separated list of SSH
targets. It defaults to an empty string so the Raspberry Pi Gitea host is not
cleaned unless you explicitly include it.
targets. It defaults to an empty string so worker nodes are not cleaned unless
you explicitly include them.
## Website App
@ -713,7 +712,7 @@ website image that points at it:
```
Ollama must also listen on the Debian host LAN address so Kubernetes pods on
other nodes can reach `OLLAMA_HOST=http://192.168.100.68:11434`:
other nodes can reach `OLLAMA_HOST=http://192.168.100.73:11434`:
```bash
./lab.sh website-ollama-listen
@ -747,7 +746,7 @@ immutable. The Kyverno supply-chain policy mutates admitted pods to the verified
image digest, so the workload runs the same digest that was signed and attested.
After `./lab.sh apps`, the live deployment image should be a content-hash tag,
for example `192.168.100.68:30500/php-website:src-...`. If it still shows
for example `192.168.100.73:30500/php-website:src-...`. If it still shows
`php-website:latest`, Argo CD has not rendered the current Application source.
Check the `website-production` Application source, sync status, and repository
access before restarting pods.

View File

@ -25,7 +25,7 @@ spec:
fsGroupChangePolicy: OnRootMismatch
containers:
- name: demos-static
image: 192.168.100.68:30500/demos-static:latest
image: 192.168.100.73:30500/demos-static:latest
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false

View File

@ -69,7 +69,7 @@ spec:
- name: N8N_RUNNERS_ENABLED
value: "true"
- name: OLLAMA_BASE_URL
value: http://192.168.100.68:11434
value: http://192.168.100.73:11434
ports:
- containerPort: 5678
name: http

View File

@ -32,8 +32,8 @@ spec:
resources:
- pods
matchImageReferences:
- glob: "192.168.100.68:30500/php-website:*"
- glob: "192.168.100.68:30500/demos-static:*"
- glob: "192.168.100.73:30500/php-website:*"
- glob: "192.168.100.73:30500/demos-static:*"
validationConfigurations:
mutateDigest: true
required: true

View File

@ -86,7 +86,7 @@ RUN rm -f /var/www/localhost/htdocs/index.html && \
chmod 0755 /usr/local/bin/start-website
ENV WEBSITE_LANG_WRITE_DIR=/var/www/localhost/htdocs/db/lang
ENV OLLAMA_HOST=http://192.168.100.68:11434
ENV OLLAMA_HOST=http://192.168.100.73:11434
ENV OLLAMA_MODEL=website-translator
USER apache

View File

@ -64,7 +64,7 @@ translations back to Redis with a TTL, then returns results in the original
order. The browser never calls the private Ollama address directly.
n8n is deployed separately at `https://n8n.lab2025.duckdns.org` and receives
`OLLAMA_BASE_URL=http://192.168.100.68:11434` so workflows can prewarm
`OLLAMA_BASE_URL=http://192.168.100.73:11434` so workflows can prewarm
translations or run batch jobs against the Debian-host Ollama API.
## Translation Observability

View File

@ -1,4 +1,4 @@
[registry."192.168.100.68:30500"]
[registry."192.168.100.73:30500"]
http = true
insecure = true

View File

@ -181,7 +181,7 @@ $blogHref = 'blog.php?lang=' . urlencode($lang);
<rect class="tree-trunk" x="468" y="650" width="104" height="142" rx="12"></rect>
<text class="tree-trunk-text" x="520" y="700">Debian</text>
<text class="tree-trunk-text tree-small" x="520" y="722">control plane</text>
<text class="tree-trunk-text tree-small" x="520" y="744">192.168.100.68</text>
<text class="tree-trunk-text tree-small" x="520" y="744">192.168.100.73</text>
<path class="tree-root" d="M520 790 C456 814 390 822 310 822"></path>
<path class="tree-root" d="M520 790 C584 816 660 824 740 822"></path>

View File

@ -211,7 +211,7 @@ if (!$texts || count($texts) > 240 || $totalLength > 80000) {
translate_response(400, ['error' => 'Invalid translation batch']);
}
$ollamaHost = rtrim(getenv('OLLAMA_HOST') ?: 'http://192.168.100.68:11434', '/');
$ollamaHost = rtrim(getenv('OLLAMA_HOST') ?: 'http://192.168.100.73:11434', '/');
$ollamaModel = getenv('OLLAMA_MODEL') ?: 'llama3.2:3b';
$cachePrefix = getenv('TRANSLATION_CACHE_PREFIX') ?: 'translation:v1';
$cacheKeys = [];

View File

@ -69,7 +69,7 @@ spec:
- name: WEBSITE_IDEAS_WRITE_DIR
value: /var/www/localhost/htdocs/db/ideas
- name: OLLAMA_HOST
value: http://192.168.100.68:11434
value: http://192.168.100.73:11434
- name: OLLAMA_MODEL
value: website-translator
- name: TRANSLATION_REDIS_HOST

View File

@ -10,7 +10,7 @@ variable "argocd_namespace" {
variable "gitops_repo_url" {
type = string
default = "ssh://git@192.168.100.89:32222/jv/my-homelab-configs.git"
default = "ssh://git@192.168.100.73:32222/jv/my-homelab-configs.git"
}
variable "website_image_ref" {

View File

@ -14,7 +14,7 @@ variable "control_plane_node_labels" {
variable "control_plane_advertise_address" {
type = string
default = "192.168.100.68"
default = "192.168.100.73"
}
variable "pod_network_cidr" {
@ -34,7 +34,7 @@ variable "kubeconfig_owner" {
variable "registry_endpoint" {
type = string
default = "192.168.100.68:30500"
default = "192.168.100.73:30500"
}
variable "node_dns_servers" {

View File

@ -72,7 +72,7 @@ variable "gitea_backend_port" {
variable "gitea_backend_host" {
type = string
default = "192.168.100.89"
default = "192.168.100.73"
}
variable "haproxy_stats_user" {

View File

@ -20,7 +20,7 @@ variable "calico_operator_node_name" {
variable "gitops_repo_url" {
type = string
default = "ssh://git@192.168.100.89:32222/jv/my-homelab-configs.git"
default = "ssh://git@192.168.100.73:32222/jv/my-homelab-configs.git"
}
variable "gitops_ssh_key_path" {

View File

@ -60,7 +60,7 @@ generates a unique fallback name using `TF_VAR_clone_hostname_prefix`.
Create an arm64 VM in Pimox with UEFI firmware, a virtio disk, and a NIC on the same LAN as the Debian provisioning host. Put network boot first.
PXE should load `grubaa64.efi`, boot the Debian installer, fetch the preseed from `http://192.168.100.68:8088/preseed/debian13-arm64-worker.cfg`, and install the golden image.
PXE should load `grubaa64.efi`, boot the Debian installer, fetch the preseed from `http://192.168.100.73:8088/preseed/debian13-arm64-worker.cfg`, and install the golden image.
If your Pimox firmware needs a different Debian arm64 EFI loader, override `TF_VAR_pxe_boot_file`.

View File

@ -1,6 +1,6 @@
variable "provisioning_host" {
type = string
default = "192.168.100.68"
default = "192.168.100.73"
}
variable "provisioning_user" {
@ -29,7 +29,7 @@ variable "proxy_dhcp_range" {
variable "http_host" {
type = string
default = "192.168.100.68"
default = "192.168.100.73"
}
variable "http_port" {
@ -138,7 +138,7 @@ variable "kernel_cgroup_boot_options" {
variable "registry_endpoint" {
type = string
default = "192.168.100.68:30500"
default = "192.168.100.73:30500"
}
variable "node_dns_servers" {

View File

@ -2,14 +2,14 @@
Gitea is bootstrap infrastructure, not a Kubernetes workload.
`lab.sh deploy-gitea` copies `docker-compose.yml` to the Raspberry Pi and runs
`lab.sh deploy-gitea` copies `docker-compose.yml` to the Debian host and runs
Gitea as an always-on Docker Compose service. The current default stores data on
the Raspberry Pi SSD under `/data/homelab-gitea/data`; the Pi Docker root is
also expected to live on the SSD-backed `/data` mount.
the HP laptop NVMe under `/data/homelab-gitea/data`; Docker root is also
expected to live on the `/data` storage path.
Defaults:
- host: `192.168.100.89`
- host: `192.168.100.73`
- user: `jv`
- install dir: `/data/homelab-gitea`
- HTTP port: `3000`
@ -25,14 +25,14 @@ adds the Debian host deploy key when needed, and points the Debian checkout's
`gitea` remote at:
```text
ssh://git@192.168.100.89:32222/jv/my-homelab-configs.git
ssh://git@192.168.100.73:32222/jv/my-homelab-configs.git
```
Argo CD does not read from the Raspberry Pi Gitea SSH port. It reads from the
Argo CD does not read from the Gitea SSH port. It reads from the
Debian bare GitOps mirror through `gitops_repo_url`, normally:
```text
ssh://jv@192.168.100.68/home/jv/git-server/my-homelab-configs.git
ssh://jv@192.168.100.73/home/jv/git-server/my-homelab-configs.git
```
The platform bootstrap registers that repo secret and updates
@ -40,6 +40,6 @@ The platform bootstrap registers that repo secret and updates
refresh the Debian host key in that ConfigMap and restart `argocd-repo-server`.
Backups are installed on the Debian host by `lab.sh deploy-gitea` and
`lab.sh backup-gitea`. The timer runs `gitea dump` inside the Raspberry Pi
container, copies the archive to Debian, and stores it under
`lab.sh backup-gitea`. The timer runs `gitea dump` inside the Gitea container,
copies the archive to Debian, and stores it under
`/home/jv/backups/gitea`.

20
lab.sh
View File

@ -212,7 +212,7 @@ adopt_apps_existing_resources() {
ensure_homelab_node_labels() {
local control_plane_node="${LAB_CONTROL_PLANE_NODE_NAME:-debian}"
local raspberry_node="${LAB_RASPBERRY_NODE_NAME:-raspberry}"
local prometheus_selector="homelab.dev/node-role=app,homelab.dev/storage=nvme"
local prometheus_selector="homelab.dev/node-role=app,homelab.dev/storage=ssd"
local node
local target_nodes
@ -236,7 +236,7 @@ ensure_homelab_node_labels() {
if [[ "${node}" == pimox-worker-* ]]; then
kubectl --kubeconfig "${KUBECONFIG_PATH}" label node "${node}" \
homelab.dev/node-role=app \
homelab.dev/storage=nvme \
homelab.dev/storage=ssd \
homelab.dev/workload-class=platform \
--overwrite
elif [[ "${node}" == "${raspberry_node}" ]]; then
@ -813,7 +813,7 @@ write_cluster_worker_var_file() {
LAB_RASPBERRY_NODE_NAME="${LAB_RASPBERRY_NODE_NAME:-raspberry}" \
LAB_RASPBERRY_SSH_KEY_PATH="${LAB_RASPBERRY_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}" \
LAB_RASPBERRY_NODE_LABELS_JSON="${LAB_RASPBERRY_NODE_LABELS_JSON:-{\"node-role.kubernetes.io/worker\":\"worker\",\"homelab.dev/node-role\":\"edge-app\",\"homelab.dev/storage\":\"local\",\"homelab.dev/workload-class\":\"edge\"}}" \
LAB_PIMOX_WORKER_NODE_LABELS_JSON="${LAB_PIMOX_WORKER_NODE_LABELS_JSON:-{\"node-role.kubernetes.io/worker\":\"worker\",\"homelab.dev/node-role\":\"app\",\"homelab.dev/storage\":\"nvme\",\"homelab.dev/workload-class\":\"platform\"}}" \
LAB_PIMOX_WORKER_NODE_LABELS_JSON="${LAB_PIMOX_WORKER_NODE_LABELS_JSON:-{\"node-role.kubernetes.io/worker\":\"worker\",\"homelab.dev/node-role\":\"app\",\"homelab.dev/storage\":\"ssd\",\"homelab.dev/workload-class\":\"platform\"}}" \
python3 - "${spec_file}" "${var_file}" <<'PY'
import json
import os
@ -2046,8 +2046,8 @@ wait_for_deployment_ready() {
deploy_gitea() {
local mode="${LAB_GITEA_DEPLOY:-true}"
local gitea_host="${LAB_GITEA_HOST:-${LAB_RASPBERRY_HOST:-192.168.100.89}}"
local gitea_user="${LAB_GITEA_USER:-${LAB_RASPBERRY_USER:-jv}}"
local gitea_host="${LAB_GITEA_HOST:-192.168.100.73}"
local gitea_user="${LAB_GITEA_USER:-jv}"
local gitea_key="${LAB_GITEA_SSH_KEY_PATH:-${LAB_RASPBERRY_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}}"
local install_dir="${LAB_GITEA_INSTALL_DIR:-/data/homelab-gitea}"
local image="${LAB_GITEA_IMAGE:-gitea/gitea:1.21.7}"
@ -2398,8 +2398,8 @@ ensure_gitea_repo_ssh_access() {
bootstrap_gitea_repo() {
local mode="${LAB_GITEA_REPO_BOOTSTRAP:-true}"
local gitea_host="${LAB_GITEA_HOST:-${LAB_RASPBERRY_HOST:-192.168.100.89}}"
local gitea_user="${LAB_GITEA_USER:-${LAB_RASPBERRY_USER:-jv}}"
local gitea_host="${LAB_GITEA_HOST:-192.168.100.73}"
local gitea_user="${LAB_GITEA_USER:-jv}"
local gitea_key="${LAB_GITEA_SSH_KEY_PATH:-${LAB_RASPBERRY_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}}"
local container_name="${LAB_GITEA_CONTAINER_NAME:-homelab-gitea}"
local http_port="${LAB_GITEA_HTTP_PORT:-3000}"
@ -2599,8 +2599,8 @@ ASKPASS_EOT
}
install_gitea_backup_timer() {
local gitea_host="${LAB_GITEA_HOST:-${LAB_RASPBERRY_HOST:-192.168.100.89}}"
local gitea_user="${LAB_GITEA_USER:-${LAB_RASPBERRY_USER:-jv}}"
local gitea_host="${LAB_GITEA_HOST:-192.168.100.73}"
local gitea_user="${LAB_GITEA_USER:-jv}"
local gitea_key="${LAB_GITEA_SSH_KEY_PATH:-${LAB_RASPBERRY_SSH_KEY_PATH:-/home/jv/.ssh/id_ed25519}}"
local gitea_container="${LAB_GITEA_CONTAINER_NAME:-homelab-gitea}"
local backup_dir="${LAB_GITEA_BACKUP_DIR:-/home/jv/backups/gitea}"
@ -3165,7 +3165,7 @@ rebuild_cluster() {
export LAB_PIMOX_WORKER_REPLACE_EXISTING="${LAB_PIMOX_WORKER_REPLACE_EXISTING:-true}"
export TF_VAR_force_worker_rejoin="${TF_VAR_force_worker_rejoin:-true}"
echo "Rebuilding the Kubernetes cluster without touching external Raspberry Pi Gitea..."
echo "Rebuilding the Kubernetes cluster without touching external Gitea..."
nuke
run_pimox_pipeline