Merge pull request 'C1: migrate homepage dashboard from minikube to ringtail (nix-built amd64)' (#348) from homepage-to-ringtail into main
This commit is contained in:
commit
ad7a0ed105
6 changed files with 194 additions and 61 deletions
|
|
@ -14,7 +14,7 @@ spec:
|
||||||
targetRevision: main
|
targetRevision: main
|
||||||
path: argocd/manifests/homepage
|
path: argocd/manifests/homepage
|
||||||
destination:
|
destination:
|
||||||
server: https://kubernetes.default.svc
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
namespace: homepage
|
namespace: homepage
|
||||||
syncPolicy:
|
syncPolicy:
|
||||||
syncOptions:
|
syncOptions:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ resources:
|
||||||
|
|
||||||
images:
|
images:
|
||||||
- name: registry.ops.eblu.me/blumeops/homepage
|
- name: registry.ops.eblu.me/blumeops/homepage
|
||||||
newTag: v1.11.0-e375859
|
newTag: v1.11.0-b87f62e-nix
|
||||||
|
|
||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: homepage-config
|
- name: homepage-config
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
# Homepage runs on ringtail (k3s) — its k8s autodiscovery only sees ringtail
|
||||||
|
# Ingresses (frigate→NVR, authentik, ntfy, ollama). Services that live on
|
||||||
|
# minikube (and indri-native) need explicit static entries here.
|
||||||
- Host Services:
|
- Host Services:
|
||||||
- Forgejo:
|
- Forgejo:
|
||||||
href: https://forge.eblu.me
|
href: https://forge.eblu.me
|
||||||
|
|
@ -57,10 +60,6 @@
|
||||||
# type: caddy
|
# type: caddy
|
||||||
# url: http://indri.tail8d86e.ts.net:2019
|
# url: http://indri.tail8d86e.ts.net:2019
|
||||||
- Home:
|
- Home:
|
||||||
- NVR:
|
|
||||||
href: https://nvr.ops.eblu.me
|
|
||||||
icon: frigate.png
|
|
||||||
description: Network video recorder
|
|
||||||
- Jellyfin:
|
- Jellyfin:
|
||||||
href: https://jellyfin.ops.eblu.me
|
href: https://jellyfin.ops.eblu.me
|
||||||
icon: jellyfin
|
icon: jellyfin
|
||||||
|
|
@ -72,15 +71,61 @@
|
||||||
enableBlocks: true
|
enableBlocks: true
|
||||||
enableNowPlaying: false
|
enableNowPlaying: false
|
||||||
fields: ["movies", "series", "episodes"]
|
fields: ["movies", "series", "episodes"]
|
||||||
|
- Mealie:
|
||||||
|
href: https://meals.ops.eblu.me
|
||||||
|
icon: mealie.png
|
||||||
|
description: Recipe manager
|
||||||
|
- DJ:
|
||||||
|
href: https://dj.ops.eblu.me
|
||||||
|
icon: navidrome.png
|
||||||
|
description: Music streaming server
|
||||||
|
widget:
|
||||||
|
type: navidrome
|
||||||
|
url: https://dj.ops.eblu.me
|
||||||
|
user: "{{HOMEPAGE_VAR_NAVIDROME_USER}}"
|
||||||
|
token: "{{HOMEPAGE_VAR_NAVIDROME_TOKEN}}"
|
||||||
|
salt: "{{HOMEPAGE_VAR_NAVIDROME_SALT}}"
|
||||||
|
- Paperless:
|
||||||
|
href: https://paperless.ops.eblu.me
|
||||||
|
icon: paperless-ngx.png
|
||||||
|
description: Document management
|
||||||
|
- Content:
|
||||||
|
- Immich:
|
||||||
|
href: https://photos.ops.eblu.me
|
||||||
|
icon: immich.png
|
||||||
|
description: Photo management
|
||||||
|
- Kiwix:
|
||||||
|
href: https://kiwix.ops.eblu.me
|
||||||
|
icon: kiwix.png
|
||||||
|
description: Offline Wikipedia
|
||||||
|
- Miniflux:
|
||||||
|
href: https://feed.ops.eblu.me
|
||||||
|
icon: miniflux.png
|
||||||
|
description: RSS reader
|
||||||
|
widget:
|
||||||
|
type: miniflux
|
||||||
|
url: https://feed.ops.eblu.me
|
||||||
|
key: "{{HOMEPAGE_VAR_MINIFLUX_API_KEY}}"
|
||||||
|
fields: ["unread"]
|
||||||
- Infrastructure:
|
- Infrastructure:
|
||||||
- Authentik:
|
- ArgoCD:
|
||||||
href: https://authentik.ops.eblu.me
|
href: https://argocd.ops.eblu.me
|
||||||
icon: authentik
|
icon: argo-cd.png
|
||||||
description: Identity provider
|
description: GitOps CD
|
||||||
- Ntfy:
|
- Grafana:
|
||||||
href: https://ntfy.ops.eblu.me
|
href: https://grafana.ops.eblu.me
|
||||||
icon: ntfy.png
|
icon: grafana.png
|
||||||
description: Push notifications
|
description: Metrics dashboards
|
||||||
|
widget:
|
||||||
|
type: grafana
|
||||||
|
url: https://grafana.ops.eblu.me
|
||||||
|
username: "{{HOMEPAGE_VAR_GRAFANA_USERNAME}}"
|
||||||
|
password: "{{HOMEPAGE_VAR_GRAFANA_PASSWORD}}"
|
||||||
|
fields: ["dashboards", "totalalerts", "alertstriggered"]
|
||||||
|
- Prometheus:
|
||||||
|
href: https://prometheus.ops.eblu.me
|
||||||
|
icon: prometheus.png
|
||||||
|
description: Metrics storage
|
||||||
- Services:
|
- Services:
|
||||||
# CV and Docs were previously auto-discovered from k8s Ingresses; after
|
# CV and Docs were previously auto-discovered from k8s Ingresses; after
|
||||||
# the indri-native migration ([[cv-on-indri]], [[docs-on-indri]]) there
|
# the indri-native migration ([[cv-on-indri]], [[docs-on-indri]]) there
|
||||||
|
|
@ -93,3 +138,11 @@
|
||||||
href: https://docs.eblu.me
|
href: https://docs.eblu.me
|
||||||
icon: mdi-book-open-page-variant
|
icon: mdi-book-open-page-variant
|
||||||
description: BlumeOps Documentation
|
description: BlumeOps Documentation
|
||||||
|
- TeslaMate:
|
||||||
|
href: https://tesla.ops.eblu.me
|
||||||
|
icon: teslamate.png
|
||||||
|
description: Tesla data logger
|
||||||
|
- Transmission:
|
||||||
|
href: https://torrent.ops.eblu.me
|
||||||
|
icon: transmission.png
|
||||||
|
description: Torrent client
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# Homepage - self-hosted services dashboard
|
|
||||||
# Two-stage build: Node.js build, Alpine runtime
|
|
||||||
|
|
||||||
ARG CONTAINER_APP_VERSION=v1.11.0
|
|
||||||
ARG HOMEPAGE_VERSION=${CONTAINER_APP_VERSION}
|
|
||||||
|
|
||||||
FROM node:24-slim AS builder
|
|
||||||
|
|
||||||
ARG HOMEPAGE_VERSION
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN git clone --depth 1 --branch ${HOMEPAGE_VERSION} \
|
|
||||||
https://forge.ops.eblu.me/mirrors/homepage.git /app
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
RUN mkdir -p config \
|
|
||||||
&& corepack enable && corepack prepare pnpm@latest --activate \
|
|
||||||
&& pnpm install --frozen-lockfile \
|
|
||||||
&& NEXT_TELEMETRY_DISABLED=1 pnpm run build
|
|
||||||
|
|
||||||
FROM node:24-alpine
|
|
||||||
|
|
||||||
ARG CONTAINER_APP_VERSION
|
|
||||||
LABEL org.opencontainers.image.title="Homepage"
|
|
||||||
LABEL org.opencontainers.image.description="A self-hosted services landing page"
|
|
||||||
LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}"
|
|
||||||
LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops"
|
|
||||||
LABEL org.opencontainers.image.vendor="blumeops"
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --from=builder --chown=1000:1000 /app/public ./public
|
|
||||||
COPY --from=builder --chown=1000:1000 /app/.next/standalone/ ./
|
|
||||||
COPY --from=builder --chown=1000:1000 /app/.next/static/ ./.next/static
|
|
||||||
|
|
||||||
RUN mkdir -p /app/config && chown 1000:1000 /app/config
|
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
ENV PORT=3000
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=20s \
|
|
||||||
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:3000/api/healthcheck || exit 1
|
|
||||||
|
|
||||||
USER 1000
|
|
||||||
CMD ["node", "server.js"]
|
|
||||||
119
containers/homepage/default.nix
Normal file
119
containers/homepage/default.nix
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Nix-built gethomepage/homepage dashboard
|
||||||
|
# Builds v1.11.0 from forge mirror.
|
||||||
|
#
|
||||||
|
# Adapted from nixpkgs pkgs/by-name/ho/homepage-dashboard (commit master),
|
||||||
|
# changed to fetch from our forge mirror and wrap with dockerTools for an
|
||||||
|
# amd64 image runnable on ringtail's k3s.
|
||||||
|
#
|
||||||
|
# The preBuild substitutions are not optional — without them Next.js writes
|
||||||
|
# its file-system-cache to a read-only path and prerender state breaks after
|
||||||
|
# restart (nixpkgs issues #328621 and #458494).
|
||||||
|
{ pkgs ? import <nixpkgs> { } }:
|
||||||
|
|
||||||
|
let
|
||||||
|
version = "1.11.0";
|
||||||
|
|
||||||
|
homepage = pkgs.stdenv.mkDerivation (finalAttrs: {
|
||||||
|
pname = "homepage-dashboard";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://forge.ops.eblu.me/mirrors/homepage.git";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-jnv9PnClm/jIQ4uU6c4A1UiAmwoihG0l6k3fUbD47I4=";
|
||||||
|
};
|
||||||
|
|
||||||
|
pnpmDeps = pkgs.fetchPnpmDeps {
|
||||||
|
inherit (finalAttrs) pname version src;
|
||||||
|
pnpm = pkgs.pnpm_10;
|
||||||
|
fetcherVersion = 3;
|
||||||
|
hash = "sha256-X5j9XppbcasGuC7fUsj4XzbaQFM9WcRcXjgJHN/inR8=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.makeBinaryWrapper
|
||||||
|
pkgs.nodejs_24
|
||||||
|
pkgs.pnpmConfigHook
|
||||||
|
pkgs.pnpm_10
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.nodePackages.node-gyp-build
|
||||||
|
];
|
||||||
|
|
||||||
|
env.PYTHON = "${pkgs.python3}/bin/python";
|
||||||
|
|
||||||
|
preBuild = ''
|
||||||
|
substituteInPlace node_modules/next/dist/server/lib/incremental-cache/file-system-cache.js \
|
||||||
|
--replace-fail 'this.serverDistDir = ctx.serverDistDir;' \
|
||||||
|
'this.serverDistDir = require("path").join((process.env.NIXPKGS_HOMEPAGE_CACHE_DIR || "/tmp/homepage-cache"), "homepage");'
|
||||||
|
|
||||||
|
for bundle in node_modules/next/dist/compiled/next-server/*.runtime.prod.js; do
|
||||||
|
substituteInPlace "$bundle" \
|
||||||
|
--replace-fail 'this.serverDistDir=e.serverDistDir' \
|
||||||
|
'this.serverDistDir=(process.env.NIXPKGS_HOMEPAGE_CACHE_DIR||"/tmp/homepage-cache")+"/homepage"'
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
mkdir -p config
|
||||||
|
pnpm build
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
mkdir -p $out/{bin,share}
|
||||||
|
cp -r .next/standalone $out/share/homepage/
|
||||||
|
cp -r public $out/share/homepage/public
|
||||||
|
chmod +x $out/share/homepage/server.js
|
||||||
|
|
||||||
|
mkdir -p $out/share/homepage/.next
|
||||||
|
cp -r .next/static $out/share/homepage/.next/static
|
||||||
|
|
||||||
|
makeWrapper "${pkgs.lib.getExe pkgs.nodejs_24}" $out/bin/homepage \
|
||||||
|
--set-default PORT 3000 \
|
||||||
|
--set-default HOMEPAGE_CONFIG_DIR /app/config \
|
||||||
|
--set-default NIXPKGS_HOMEPAGE_CACHE_DIR /tmp/homepage-cache \
|
||||||
|
--add-flags "$out/share/homepage/server.js" \
|
||||||
|
--prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.unixtools.ping ]}"
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
doDist = false;
|
||||||
|
});
|
||||||
|
in
|
||||||
|
|
||||||
|
pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "blumeops/homepage";
|
||||||
|
contents = [
|
||||||
|
homepage
|
||||||
|
pkgs.cacert
|
||||||
|
pkgs.tzdata
|
||||||
|
];
|
||||||
|
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir -p tmp
|
||||||
|
chmod 1777 tmp
|
||||||
|
'';
|
||||||
|
|
||||||
|
config = {
|
||||||
|
Entrypoint = [ "${homepage}/bin/homepage" ];
|
||||||
|
Env = [
|
||||||
|
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||||
|
"TZDIR=${pkgs.tzdata}/share/zoneinfo"
|
||||||
|
"TMPDIR=/tmp"
|
||||||
|
"NIXPKGS_HOMEPAGE_CACHE_DIR=/tmp/homepage-cache"
|
||||||
|
"HOMEPAGE_CONFIG_DIR=/app/config"
|
||||||
|
"NEXT_TELEMETRY_DISABLED=1"
|
||||||
|
"PORT=3000"
|
||||||
|
];
|
||||||
|
ExposedPorts = {
|
||||||
|
"3000/tcp" = { };
|
||||||
|
};
|
||||||
|
User = "1000";
|
||||||
|
};
|
||||||
|
}
|
||||||
8
docs/changelog.d/homepage-to-ringtail.infra.md
Normal file
8
docs/changelog.d/homepage-to-ringtail.infra.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
Migrated homepage dashboard from minikube (indri/arm64) to k3s (ringtail/amd64).
|
||||||
|
The container is now built via nix (`containers/homepage/default.nix`), adapted
|
||||||
|
from nixpkgs `homepage-dashboard` with the upstream Next.js cache patches and
|
||||||
|
wrapped with `dockerTools.buildLayeredImage`. Autodiscovery shifts: services on
|
||||||
|
minikube (ArgoCD, Immich, Kiwix, Mealie, Miniflux, Grafana, Prometheus,
|
||||||
|
Navidrome, Paperless, TeslaMate, Transmission) become explicit static entries
|
||||||
|
in `services.yaml`; ringtail services (Authentik, Frigate/NVR, Ntfy, Ollama)
|
||||||
|
auto-populate via Ingress annotations.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue