Add Jeannie status command
This commit is contained in:
parent
3b86eec2d2
commit
806efb8f85
80
README.md
80
README.md
|
|
@ -28,7 +28,7 @@ The lab is intentionally small but production-shaped:
|
||||||
Tailscale, with nginx caching, gzip, HTTP/2, TLS session reuse, and upstream
|
Tailscale, with nginx caching, gzip, HTTP/2, TLS session reuse, and upstream
|
||||||
keepalive
|
keepalive
|
||||||
|
|
||||||
Run `./lab.sh up` and `./lab.sh nuke` only from the Debian homelab server. The
|
Run `./jeannie up` and `./jeannie nuke` only from the Debian homelab server. The
|
||||||
script intentionally refuses to run from non-Debian machines so a laptop cannot
|
script intentionally refuses to run from non-Debian machines so a laptop cannot
|
||||||
accidentally modify the cluster.
|
accidentally modify the cluster.
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ accidentally modify the cluster.
|
||||||
- serves Debian 13 arm64 netboot assets through TFTP and HTTP
|
- serves Debian 13 arm64 netboot assets through TFTP and HTTP
|
||||||
- creates a golden image install path with Kubernetes, containerd,
|
- creates a golden image install path with Kubernetes, containerd,
|
||||||
qemu-guest-agent, cloud-init, and storage client packages ready
|
qemu-guest-agent, cloud-init, and storage client packages ready
|
||||||
- is driven by `./lab.sh up` when Pimox is reachable, without changing
|
- is driven by `./jeannie up` when Pimox is reachable, without changing
|
||||||
Orange Pi host networking
|
Orange Pi host networking
|
||||||
|
|
||||||
2. `bootstrap/cluster`
|
2. `bootstrap/cluster`
|
||||||
|
|
@ -122,14 +122,14 @@ plane upgrade.
|
||||||
Check node versions from the Debian host:
|
Check node versions from the Debian host:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh doctor-versions
|
./jeannie doctor-versions
|
||||||
```
|
```
|
||||||
|
|
||||||
The check prints the API server, kubelet versions, kubelet minors, and containerd
|
The check prints the API server, kubelet versions, kubelet minors, and containerd
|
||||||
runtimes. It exits nonzero when kubelet minors differ from the API server minor
|
runtimes. It exits nonzero when kubelet minors differ from the API server minor
|
||||||
or when containerd major versions are mixed. The Gitea Actions auto path runs
|
or when containerd major versions are mixed. The Gitea Actions auto path runs
|
||||||
this check before app deploys; kubelet minor drift switches the job to
|
this check before app deploys; kubelet minor drift switches the job to
|
||||||
`./lab.sh rebuild-cluster` so the Pimox template and worker VMs are replaced
|
`./jeannie rebuild-cluster` so the Pimox template and worker VMs are replaced
|
||||||
from the pinned image. For Pimox workers, prefer rebuilding from the corrected
|
from the pinned image. For Pimox workers, prefer rebuilding from the corrected
|
||||||
golden template and rejoining the worker over ad hoc live package upgrades.
|
golden template and rejoining the worker over ad hoc live package upgrades.
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@ From the Debian server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/my-homelab-configs
|
cd ~/my-homelab-configs
|
||||||
./lab.sh up
|
./jeannie up
|
||||||
```
|
```
|
||||||
|
|
||||||
The script first deploys external Gitea to the Debian host with Docker Compose
|
The script first deploys external Gitea to the Debian host with Docker Compose
|
||||||
|
|
@ -170,7 +170,7 @@ must be left untouched, or set `LAB_PIMOX_WORKER_COUNT=2` to manage both VMID
|
||||||
`9010` and VMID `9011`.
|
`9010` and VMID `9011`.
|
||||||
|
|
||||||
OpenWrt firewall VM automation is available as a standalone command because it
|
OpenWrt firewall VM automation is available as a standalone command because it
|
||||||
attaches to both WAN and LAN bridges. Run `./lab.sh openwrt` after `vmbr1`
|
attaches to both WAN and LAN bridges. Run `./jeannie openwrt` after `vmbr1`
|
||||||
already exists on the Orange Pi. The pipeline downloads the OpenWrt ARM
|
already exists on the Orange Pi. The pipeline downloads the OpenWrt ARM
|
||||||
SystemReady EFI image, writes basic WAN/LAN/firewall config into the image,
|
SystemReady EFI image, writes basic WAN/LAN/firewall config into the image,
|
||||||
imports it as VM `9100`, attaches `vmbr0` as WAN and `vmbr1` as LAN, and stores
|
imports it as VM `9100`, attaches `vmbr0` as WAN and `vmbr1` as LAN, and stores
|
||||||
|
|
@ -226,9 +226,19 @@ The website should be reached through the configured public hostname, not the ra
|
||||||
OCI IP address, because the Let's Encrypt certificate is issued for the
|
OCI IP address, because the Let's Encrypt certificate is issued for the
|
||||||
hostname.
|
hostname.
|
||||||
|
|
||||||
|
Run a read-only health snapshot from the Debian server with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./jeannie status
|
||||||
|
```
|
||||||
|
|
||||||
|
It reports host memory/disk, systemd services, Docker Compose stacks,
|
||||||
|
Kubernetes health when the API is reachable, Pimox worker VM status, Tailscale,
|
||||||
|
and key local/public HTTP endpoints.
|
||||||
|
|
||||||
## Adding Nodes
|
## Adding Nodes
|
||||||
|
|
||||||
For Pimox on Orange Pi 5 Plus, `./lab.sh up` can create the Debian 13 arm64
|
For Pimox on Orange Pi 5 Plus, `./jeannie up` can create the Debian 13 arm64
|
||||||
template and worker VM clones automatically when the Orange Pi storage path is
|
template and worker VM clones automatically when the Orange Pi storage path is
|
||||||
healthy. Defaults are intentionally tied to the observed host: Pimox SSH host
|
healthy. Defaults are intentionally tied to the observed host: Pimox SSH host
|
||||||
`192.168.100.80`, bridge `vmbr0`, template VMID `9000` on `local` storage, two
|
`192.168.100.80`, bridge `vmbr0`, template VMID `9000` on `local` storage, two
|
||||||
|
|
@ -248,7 +258,7 @@ allowing higher indexes to be automated.
|
||||||
Run a full cluster rebuild from the Debian server with:
|
Run a full cluster rebuild from the Debian server with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh rebuild-cluster
|
./jeannie rebuild-cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
That path preserves external Gitea, rebuilds the Pimox template
|
That path preserves external Gitea, rebuilds the Pimox template
|
||||||
|
|
@ -262,7 +272,7 @@ To pause the Kubernetes cluster without deleting kubeadm files, OpenTofu state,
|
||||||
PV data, or VM disks, run:
|
PV data, or VM disks, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh stop-cluster
|
./jeannie stop-cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
This stops `kubelet`, stops Kubernetes CRI containers with `crictl` when
|
This stops `kubelet`, stops Kubernetes CRI containers with `crictl` when
|
||||||
|
|
@ -278,7 +288,7 @@ hard `qm stop` after timeout, and the usual `LAB_PIMOX_WORKER_COUNT`,
|
||||||
select VM workers. Resume the runtime with:
|
select VM workers. Resume the runtime with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh start-cluster
|
./jeannie start-cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
To exclude the Raspberry Pi from the Kubernetes cluster, set
|
To exclude the Raspberry Pi from the Kubernetes cluster, set
|
||||||
|
|
@ -328,7 +338,7 @@ preferred pod anti-affinity so future Argo CD, Kyverno, Prometheus operator, and
|
||||||
kube-state-metrics scheduling does not collapse onto the first worker that joins.
|
kube-state-metrics scheduling does not collapse onto the first worker that joins.
|
||||||
PVC-backed monitoring StatefulSets are intentionally treated separately because
|
PVC-backed monitoring StatefulSets are intentionally treated separately because
|
||||||
their retained OpenEBS hostpath volumes are node-local. Run
|
their retained OpenEBS hostpath volumes are node-local. Run
|
||||||
`./lab.sh move-prometheus-stack-workers` from the Debian host to label existing
|
`./jeannie move-prometheus-stack-workers` from the Debian host to label existing
|
||||||
worker nodes, destroy only the existing `prometheus-stack` Helm release, delete
|
worker nodes, destroy only the existing `prometheus-stack` Helm release, delete
|
||||||
its retained PVC/PV objects, and recreate the stack on the worker selector when
|
its retained PVC/PV objects, and recreate the stack on the worker selector when
|
||||||
you intentionally accept losing that monitoring data. A planned monitoring data
|
you intentionally accept losing that monitoring data. A planned monitoring data
|
||||||
|
|
@ -395,7 +405,7 @@ The edge stack uses Traefik as its backend by default and validates
|
||||||
subnet-route approval is not automatic in the tailnet policy, the edge deploy
|
subnet-route approval is not automatic in the tailnet policy, the edge deploy
|
||||||
will fail clearly instead of silently keeping a broken public path.
|
will fail clearly instead of silently keeping a broken public path.
|
||||||
|
|
||||||
For `./lab.sh nuke`, set `WORKER_SSH_TARGETS` to a space-separated list of
|
For `./jeannie nuke`, set `WORKER_SSH_TARGETS` to a space-separated list of
|
||||||
remote SSH targets when more worker nodes exist. Set it to an empty string for a
|
remote SSH targets when more worker nodes exist. Set it to an empty string for a
|
||||||
single-node rebuild.
|
single-node rebuild.
|
||||||
|
|
||||||
|
|
@ -423,13 +433,13 @@ and audits whether the image has both:
|
||||||
The private Cosign key, generated password, and downloaded Cosign binary live in
|
The private Cosign key, generated password, and downloaded Cosign binary live in
|
||||||
`${XDG_DATA_HOME:-$HOME/.local/share}/homelab/` by default so the signing
|
`${XDG_DATA_HOME:-$HOME/.local/share}/homelab/` by default so the signing
|
||||||
identity survives temporary checkout cleanup. Repo-local image state files still
|
identity survives temporary checkout cleanup. Repo-local image state files still
|
||||||
live under `.lab/`, which is ignored by Git. `./lab.sh apps` creates or reuses
|
live under `.lab/`, which is ignored by Git. `./jeannie apps` creates or reuses
|
||||||
the persistent Cosign key, publishes the public key into the Kyverno namespace as
|
the persistent Cosign key, publishes the public key into the Kyverno namespace as
|
||||||
`homelab-cosign-public-key`, builds images with BuildKit SBOM attestations, signs
|
`homelab-cosign-public-key`, builds images with BuildKit SBOM attestations, signs
|
||||||
the pushed images, attaches a signed SPDX SBOM predicate, and verifies both
|
the pushed images, attaches a signed SPDX SBOM predicate, and verifies both
|
||||||
artifacts before refreshing the workload Applications. The policy starts in
|
artifacts before refreshing the workload Applications. The policy starts in
|
||||||
`Audit` mode so an existing live deployment can recover while the current images
|
`Audit` mode so an existing live deployment can recover while the current images
|
||||||
are signed; after `./lab.sh apps` verifies both images, change `validationActions` in
|
are signed; after `./jeannie apps` verifies both images, change `validationActions` in
|
||||||
`apps/supply-chain-policy/local-registry-image-policy.yaml` from `Audit` to
|
`apps/supply-chain-policy/local-registry-image-policy.yaml` from `Audit` to
|
||||||
`Deny` to make it admission-enforcing. Set `COSIGN_PASSWORD` if you want to
|
`Deny` to make it admission-enforcing. Set `COSIGN_PASSWORD` if you want to
|
||||||
manage the key password externally; otherwise the Debian runner creates
|
manage the key password externally; otherwise the Debian runner creates
|
||||||
|
|
@ -513,7 +523,7 @@ certificate warning because the trusted certificate is issued for the hostname.
|
||||||
The edge stack uses HTTP-01 validation and requests one certificate covering
|
The edge stack uses HTTP-01 validation and requests one certificate covering
|
||||||
`server_name` plus `additional_server_names`. DuckDNS resolves sub-subdomains
|
`server_name` plus `additional_server_names`. DuckDNS resolves sub-subdomains
|
||||||
under `lab2025.duckdns.org` to the same edge IP, so inbound TCP 80 and 443 must
|
under `lab2025.duckdns.org` to the same edge IP, so inbound TCP 80 and 443 must
|
||||||
be open before `./lab.sh up` runs. Set `TF_VAR_letsencrypt_email` to receive
|
be open before `./jeannie up` runs. Set `TF_VAR_letsencrypt_email` to receive
|
||||||
expiry notices, or leave it empty to register without an email. Set
|
expiry notices, or leave it empty to register without an email. Set
|
||||||
`TF_VAR_enable_letsencrypt=false` to keep using the temporary local certificate.
|
`TF_VAR_enable_letsencrypt=false` to keep using the temporary local certificate.
|
||||||
|
|
||||||
|
|
@ -523,7 +533,7 @@ Add Kubernetes manifests under `apps/<name>` and register them in
|
||||||
`bootstrap/apps`'s `applications` map. Argo CD will own sync, pruning, and
|
`bootstrap/apps`'s `applications` map. Argo CD will own sync, pruning, and
|
||||||
self-healing for the app.
|
self-healing for the app.
|
||||||
|
|
||||||
The `heimdall` app is intentionally waited on at the end of `./lab.sh apps`.
|
The `heimdall` app is intentionally waited on at the end of `./jeannie apps`.
|
||||||
It runs the LinuxServer.io Heimdall dashboard, persists `/config` on
|
It runs the LinuxServer.io Heimdall dashboard, persists `/config` on
|
||||||
OpenEBS, and seeds tiles for the website, demo apps, Gitea, Grafana,
|
OpenEBS, and seeds tiles for the website, demo apps, Gitea, Grafana,
|
||||||
Prometheus, Alertmanager, Argo CD, the local registry, and Heimdall itself.
|
Prometheus, Alertmanager, Argo CD, the local registry, and Heimdall itself.
|
||||||
|
|
@ -598,12 +608,12 @@ restart `argocd-repo-server`, and hard-refresh the affected Application.
|
||||||
Deploy or refresh the external Gitea container from the Debian host with:
|
Deploy or refresh the external Gitea container from the Debian host with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh deploy-gitea
|
./jeannie deploy-gitea
|
||||||
```
|
```
|
||||||
|
|
||||||
## Gitea Backups
|
## Gitea Backups
|
||||||
|
|
||||||
`./lab.sh up` installs a Debian-host systemd timer named
|
`./jeannie up` installs a Debian-host systemd timer named
|
||||||
`homelab-gitea-backup.timer`. The timer runs daily, SSHes to the configured
|
`homelab-gitea-backup.timer`. The timer runs daily, SSHes to the configured
|
||||||
Gitea host, executes `gitea dump` inside the Gitea Docker container, copies the
|
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
|
dump back to Debian, and stores it under `/home/jv/backups/gitea`. The default
|
||||||
|
|
@ -618,13 +628,13 @@ does not write into the live Gitea data directory.
|
||||||
Run a manual backup from the Debian server with:
|
Run a manual backup from the Debian server with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh backup-gitea
|
./jeannie backup-gitea
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the restore drill manually with:
|
Run the restore drill manually with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh drill-gitea-restore
|
./jeannie drill-gitea-restore
|
||||||
```
|
```
|
||||||
|
|
||||||
Useful checks:
|
Useful checks:
|
||||||
|
|
@ -646,16 +656,16 @@ a repository-scoped Debian host runner with the label `homelab-debian`.
|
||||||
The workflow only blocks automatic deploy for external Gitea service
|
The workflow only blocks automatic deploy for external Gitea service
|
||||||
changes: files under `infra/gitea/`, or edits inside the `deploy_gitea`,
|
changes: files under `infra/gitea/`, or edits inside the `deploy_gitea`,
|
||||||
`install_gitea_backup_timer`, `backup_gitea`, or `drill_gitea_restore`
|
`install_gitea_backup_timer`, `backup_gitea`, or `drill_gitea_restore`
|
||||||
functions in `lab.sh`. Other changes use `HOMELAB_ACTION_COMMAND=auto` by
|
functions in `jeannie`. Other changes use `HOMELAB_ACTION_COMMAND=auto` by
|
||||||
default: Actions runs `./lab.sh doctor-versions` when the Debian runner already
|
default: Actions runs `./jeannie doctor-versions` when the Debian runner already
|
||||||
has a cluster kubeconfig. If node versions are aligned it runs `./lab.sh apps`;
|
has a cluster kubeconfig. If node versions are aligned it runs `./jeannie apps`;
|
||||||
if kubelet minor drift is detected it runs `./lab.sh rebuild-cluster`; if no
|
if kubelet minor drift is detected it runs `./jeannie rebuild-cluster`; if no
|
||||||
kubeconfig exists it also runs `./lab.sh rebuild-cluster`.
|
kubeconfig exists it also runs `./jeannie rebuild-cluster`.
|
||||||
|
|
||||||
Set `HOMELAB_ACTION_COMMAND=apps` or `HOMELAB_ACTION_COMMAND=rebuild-cluster`
|
Set `HOMELAB_ACTION_COMMAND=apps` or `HOMELAB_ACTION_COMMAND=rebuild-cluster`
|
||||||
on the runner to force one path.
|
on the runner to force one path.
|
||||||
|
|
||||||
`./lab.sh bootstrap-gitea-repo` also registers the Debian host SSH public key
|
`./jeannie bootstrap-gitea-repo` also registers the Debian host SSH public key
|
||||||
with the Gitea repository and switches the Debian working copy's `gitea` remote
|
with the Gitea repository and switches the Debian working copy's `gitea` remote
|
||||||
to `ssh://git@192.168.100.73: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
|
is `/home/jv/.ssh/id_ed25519.pub`; set `LAB_GITEA_REPO_SSH_KEY_PATH` to use a
|
||||||
|
|
@ -677,7 +687,7 @@ Register and start the Debian runner from the Debian server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/my-homelab-configs
|
cd ~/my-homelab-configs
|
||||||
GITEA_RUNNER_REGISTRATION_TOKEN='<repo-runner-token>' ./lab.sh install-gitea-runner
|
GITEA_RUNNER_REGISTRATION_TOKEN='<repo-runner-token>' ./jeannie install-gitea-runner
|
||||||
```
|
```
|
||||||
|
|
||||||
The runner is installed as `homelab-gitea-runner.service`, runs as user `jv`, and
|
The runner is installed as `homelab-gitea-runner.service`, runs as user `jv`, and
|
||||||
|
|
@ -700,12 +710,12 @@ journalctl -u homelab-gitea-runner.service -n 100 --no-pager
|
||||||
providers, Helm chart versions, and the pinned tools used by the Gitea Actions
|
providers, Helm chart versions, and the pinned tools used by the Gitea Actions
|
||||||
workflow. Renovate should open reviewable update branches or PRs only; it must
|
workflow. Renovate should open reviewable update branches or PRs only; it must
|
||||||
not auto-merge infrastructure changes. Keep app-only dependency updates on the
|
not auto-merge infrastructure changes. Keep app-only dependency updates on the
|
||||||
normal Gitea Actions path, and run `./lab.sh up` manually on the Debian server
|
normal Gitea Actions path, and run `./jeannie up` manually on the Debian server
|
||||||
for platform or provisioning updates.
|
for platform or provisioning updates.
|
||||||
|
|
||||||
## Destructive Rebuilds
|
## Destructive Rebuilds
|
||||||
|
|
||||||
`./lab.sh nuke` resets kubeadm, containerd runtime state, CNI files, Calico
|
`./jeannie nuke` resets kubeadm, containerd runtime state, CNI files, Calico
|
||||||
links, iptables rules, and local OpenTofu state. It does not delete retained data
|
links, iptables rules, and local OpenTofu state. It does not delete retained data
|
||||||
under `/data/openebs/local`.
|
under `/data/openebs/local`.
|
||||||
|
|
||||||
|
|
@ -735,14 +745,14 @@ Create or refresh the Ollama model on the Debian server before deploying a
|
||||||
website image that points at it:
|
website image that points at it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh website-translation-model
|
./jeannie website-translation-model
|
||||||
```
|
```
|
||||||
|
|
||||||
Ollama must also listen on the Debian host LAN address so Kubernetes pods on
|
Ollama must also listen on the Debian host LAN address so Kubernetes pods on
|
||||||
other nodes can reach `OLLAMA_HOST=http://192.168.100.73:11434`:
|
other nodes can reach `OLLAMA_HOST=http://192.168.100.73:11434`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./lab.sh website-ollama-listen
|
./jeannie website-ollama-listen
|
||||||
```
|
```
|
||||||
|
|
||||||
The CV page has two client-side presentation modes:
|
The CV page has two client-side presentation modes:
|
||||||
|
|
@ -757,22 +767,22 @@ served from a separate `demos-static` artifact under `apps/demos-static` and are
|
||||||
published through the `demos-static` Argo CD application. Public traffic reaches
|
published through the `demos-static` Argo CD application. Public traffic reaches
|
||||||
them through the edge path at `/demo-apps/`.
|
them through the edge path at `/demo-apps/`.
|
||||||
|
|
||||||
`./lab.sh up` builds and pushes two independent images:
|
`./jeannie up` builds and pushes two independent images:
|
||||||
|
|
||||||
- a content-hash `php-website` tag generated by `lab.sh` and passed to Argo CD
|
- a content-hash `php-website` tag generated by `jeannie` and passed to Argo CD
|
||||||
as a Kustomize image override
|
as a Kustomize image override
|
||||||
- `demos-static:latest` from `apps/demos-static`
|
- `demos-static:latest` from `apps/demos-static`
|
||||||
- Cosign signatures and signed SPDX SBOM attestations for both pushed images
|
- Cosign signatures and signed SPDX SBOM attestations for both pushed images
|
||||||
|
|
||||||
The website manifest keeps the stable base image name `php-website:bootstrap`.
|
The website manifest keeps the stable base image name `php-website:bootstrap`.
|
||||||
During bootstrap, `lab.sh` hashes `apps/website`, builds
|
During bootstrap, `jeannie` hashes `apps/website`, builds
|
||||||
`<registry>/php-website:src-<hash>`, exports that exact reference through
|
`<registry>/php-website:src-<hash>`, exports that exact reference through
|
||||||
`TF_VAR_website_image_ref`, and the Argo CD Application applies it through
|
`TF_VAR_website_image_ref`, and the Argo CD Application applies it through
|
||||||
Kustomize. This keeps the GitOps source generic while the deployed image remains
|
Kustomize. This keeps the GitOps source generic while the deployed image remains
|
||||||
immutable. The Kyverno supply-chain policy mutates admitted pods to the verified
|
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.
|
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,
|
After `./jeannie apps`, the live deployment image should be a content-hash tag,
|
||||||
for example `192.168.100.73: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.
|
`php-website:latest`, Argo CD has not rendered the current Application source.
|
||||||
Check the `website-production` Application source, sync status, and repository
|
Check the `website-production` Application source, sync status, and repository
|
||||||
|
|
|
||||||
181
jeannie
181
jeannie
|
|
@ -1925,7 +1925,7 @@ if not isinstance(document, dict):
|
||||||
"documentNamespace": f"https://homelab.local/spdx/{safe_ref}/{source_hash}",
|
"documentNamespace": f"https://homelab.local/spdx/{safe_ref}/{source_hash}",
|
||||||
"creationInfo": {
|
"creationInfo": {
|
||||||
"created": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
"created": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||||
"creators": ["Tool: lab.sh"],
|
"creators": ["Tool: jeannie"],
|
||||||
},
|
},
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
|
|
@ -3430,6 +3430,180 @@ start_cluster() {
|
||||||
echo "Kubernetes runtime start requested. Use 'kubectl get nodes -o wide' to watch readiness."
|
echo "Kubernetes runtime start requested. Use 'kubectl get nodes -o wide' to watch readiness."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_section() {
|
||||||
|
printf '\n== %s ==\n' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
status_run() {
|
||||||
|
local description="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
printf '\n-- %s\n' "${description}"
|
||||||
|
if ! "$@"; then
|
||||||
|
printf 'status check failed: %s\n' "${description}" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
status_http() {
|
||||||
|
local name="$1"
|
||||||
|
local url="$2"
|
||||||
|
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
printf '%-28s ' "${name}"
|
||||||
|
curl -k -sS -o /dev/null --connect-timeout 5 --max-time 10 -w '%{http_code} %{url_effective}\n' "${url}" ||
|
||||||
|
printf 'unreachable %s\n' "${url}"
|
||||||
|
else
|
||||||
|
printf '%-28s curl not installed\n' "${name}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
status_systemd_units() {
|
||||||
|
local unit
|
||||||
|
|
||||||
|
for unit in "$@"; do
|
||||||
|
if systemctl list-unit-files --no-legend "${unit}.service" 2>/dev/null | grep -q .; then
|
||||||
|
printf '%-28s %s\n' "${unit}" "$(systemctl is-active "${unit}" 2>/dev/null || true)"
|
||||||
|
else
|
||||||
|
printf '%-28s not-installed\n' "${unit}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
status_compose_stack() {
|
||||||
|
local name="$1"
|
||||||
|
local directory="$2"
|
||||||
|
|
||||||
|
printf '\n-- Docker Compose: %s (%s)\n' "${name}" "${directory}"
|
||||||
|
if [[ ! -d "${directory}" ]]; then
|
||||||
|
printf 'missing directory\n'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
printf 'docker not installed\n'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! sudo docker compose version >/dev/null 2>&1; then
|
||||||
|
printf 'docker compose unavailable\n'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
(cd "${directory}" && sudo docker compose ps) || true
|
||||||
|
}
|
||||||
|
|
||||||
|
status_kubernetes() {
|
||||||
|
status_section "Kubernetes"
|
||||||
|
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
printf 'kubectl not installed\n'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ ! -s "${KUBECONFIG_PATH}" ]]; then
|
||||||
|
printf 'kubeconfig missing: %s\n' "${KUBECONFIG_PATH}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! kubectl --kubeconfig "${KUBECONFIG_PATH}" get --raw=/readyz >/dev/null 2>&1; then
|
||||||
|
printf 'API server not reachable through %s\n' "${KUBECONFIG_PATH}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
status_run "nodes" kubectl --kubeconfig "${KUBECONFIG_PATH}" get nodes -o wide
|
||||||
|
status_kubernetes_problem_pods
|
||||||
|
status_run "traefik services" kubectl --kubeconfig "${KUBECONFIG_PATH}" -n traefik get svc,pods -o wide
|
||||||
|
status_run "website pods" kubectl --kubeconfig "${KUBECONFIG_PATH}" -n website-production get pods -o wide
|
||||||
|
}
|
||||||
|
|
||||||
|
status_kubernetes_problem_pods() {
|
||||||
|
local rows
|
||||||
|
|
||||||
|
printf '\n-- pods not Running/Completed\n'
|
||||||
|
rows="$(
|
||||||
|
kubectl --kubeconfig "${KUBECONFIG_PATH}" get pods -A --no-headers -o wide |
|
||||||
|
awk '$4 != "Running" && $4 != "Completed" { print }'
|
||||||
|
)"
|
||||||
|
if [[ -n "${rows}" ]]; then
|
||||||
|
printf '%s\n' "${rows}"
|
||||||
|
else
|
||||||
|
printf 'none\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
status_pimox_workers() {
|
||||||
|
local pimox_host="${LAB_PIMOX_HOST:-${TF_VAR_pimox_host:-192.168.100.80}}"
|
||||||
|
local pimox_user="${LAB_PIMOX_USER:-${TF_VAR_pimox_user:-jv}}"
|
||||||
|
local pimox_key="${LAB_PIMOX_SSH_KEY_PATH:-${TF_VAR_pimox_ssh_key_path:-/home/jv/.ssh/id_ed25519}}"
|
||||||
|
local qm_bin="${LAB_PIMOX_QM_BIN:-${TF_VAR_pimox_qm_bin:-/usr/sbin/qm}}"
|
||||||
|
local worker_count="${LAB_PIMOX_WORKER_COUNT:-$(pimox_worker_count_default)}"
|
||||||
|
local worker_base_vmid="${LAB_PIMOX_WORKER_BASE_VMID:-9010}"
|
||||||
|
local worker_skip_indexes="${LAB_PIMOX_SKIP_WORKER_INDEXES:-}"
|
||||||
|
local index
|
||||||
|
local vmid
|
||||||
|
|
||||||
|
status_section "Pimox Workers"
|
||||||
|
|
||||||
|
if ! [[ "${worker_count}" =~ ^[0-9]+$ ]]; then
|
||||||
|
printf 'invalid LAB_PIMOX_WORKER_COUNT: %s\n' "${worker_count}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ((worker_count == 0)); then
|
||||||
|
printf 'worker count is 0\n'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for ((index = 1; index <= worker_count; index++)); do
|
||||||
|
if worker_index_is_skipped "${index}" "${worker_skip_indexes}"; then
|
||||||
|
printf 'worker index %s skipped\n' "${index}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
vmid=$((worker_base_vmid + index - 1))
|
||||||
|
printf 'VM %-6s ' "${vmid}"
|
||||||
|
pimox_ssh "${pimox_host}" "${pimox_user}" "${pimox_key}" "sudo '${qm_bin}' status '${vmid}'" 2>/dev/null ||
|
||||||
|
printf 'unreachable or missing\n'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
status_report() {
|
||||||
|
require_debian_server "status"
|
||||||
|
|
||||||
|
status_section "Host"
|
||||||
|
printf 'hostname: %s\n' "$(hostname -f 2>/dev/null || hostname)"
|
||||||
|
printf 'date: %s\n' "$(date -Is)"
|
||||||
|
printf 'uptime: %s\n' "$(uptime -p 2>/dev/null || uptime)"
|
||||||
|
status_run "memory" free -h
|
||||||
|
status_run "disk" df -h / /data /data/docker /data/openebs/local
|
||||||
|
|
||||||
|
status_section "Systemd"
|
||||||
|
status_systemd_units ssh docker containerd kubelet tailscaled homelab-gitea-runner
|
||||||
|
|
||||||
|
status_section "Docker"
|
||||||
|
if command -v docker >/dev/null 2>&1; then
|
||||||
|
status_run "docker containers" sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
|
||||||
|
else
|
||||||
|
printf 'docker not installed\n'
|
||||||
|
fi
|
||||||
|
status_compose_stack "gitea" "/data/homelab-gitea"
|
||||||
|
status_compose_stack "arr-stack" "${REPO_ROOT}/infra/arr-stack"
|
||||||
|
|
||||||
|
status_kubernetes
|
||||||
|
status_pimox_workers
|
||||||
|
|
||||||
|
status_section "Tailscale"
|
||||||
|
if command -v tailscale >/dev/null 2>&1; then
|
||||||
|
status_run "tailscale ip" tailscale ip -4
|
||||||
|
status_run "tailscale peers" tailscale status
|
||||||
|
else
|
||||||
|
printf 'tailscale not installed\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
status_section "HTTP"
|
||||||
|
status_http "website public" "https://lab2025.duckdns.org/"
|
||||||
|
status_http "gitea public" "https://lab2025.duckdns.org/git/"
|
||||||
|
status_http "gitea local" "http://127.0.0.1:3000/"
|
||||||
|
status_http "traefik lb" "http://192.168.100.240/"
|
||||||
|
status_http "arr radarr" "http://127.0.0.1:7878/"
|
||||||
|
status_http "arr sonarr" "http://127.0.0.1:8989/"
|
||||||
|
status_http "arr prowlarr" "http://127.0.0.1:9696/"
|
||||||
|
}
|
||||||
|
|
||||||
nuke() {
|
nuke() {
|
||||||
local worker_ssh_targets
|
local worker_ssh_targets
|
||||||
local worker_targets
|
local worker_targets
|
||||||
|
|
@ -3584,6 +3758,9 @@ case "${1:-}" in
|
||||||
start-cluster)
|
start-cluster)
|
||||||
start_cluster
|
start_cluster
|
||||||
;;
|
;;
|
||||||
|
status)
|
||||||
|
status_report
|
||||||
|
;;
|
||||||
apps)
|
apps)
|
||||||
apps
|
apps
|
||||||
;;
|
;;
|
||||||
|
|
@ -3621,7 +3798,7 @@ case "${1:-}" in
|
||||||
nuke
|
nuke
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {up|rebuild-cluster|stop-cluster|start-cluster|apps|website-translation-model|website-ollama-listen|deploy-gitea|bootstrap-gitea-repo|backup-gitea|drill-gitea-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|openwrt|nuke}"
|
echo "Usage: $0 {up|rebuild-cluster|stop-cluster|start-cluster|status|apps|website-translation-model|website-ollama-listen|deploy-gitea|bootstrap-gitea-repo|backup-gitea|drill-gitea-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|openwrt|nuke}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue