diff --git a/apps/artcraft/Chart.yaml b/apps/artcraft/Chart.yaml deleted file mode 100644 index 0305dc4..0000000 --- a/apps/artcraft/Chart.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v2 -name: artcraft-homelab -type: application -version: 0.1.0 diff --git a/apps/artcraft/files/download.py b/apps/artcraft/files/download.py deleted file mode 100644 index dfb609b..0000000 --- a/apps/artcraft/files/download.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Download and unpack an official, versioned upstream web bundle.""" -import os -from pathlib import Path -import shutil -import tempfile -import time -import urllib.request -import zipfile - -url = os.environ["RELEASE_URL"] -if not url.startswith("https://github.com/storytold/"): - raise ValueError("Expected an official storytold GitHub release URL") -with tempfile.TemporaryDirectory() as tmp: - archive = Path(tmp) / "release.zip" - for attempt in range(4): - try: - with urllib.request.urlopen(url, timeout=120) as response, archive.open("wb") as out: - shutil.copyfileobj(response, out) - break - except Exception: - if attempt == 3: - raise - time.sleep(2 ** attempt) - unpacked = Path(tmp) / "unpacked" - with zipfile.ZipFile(archive) as bundle: - for member in bundle.infolist(): - path = Path(member.filename) - if path.is_absolute() or ".." in path.parts or (member.external_attr >> 16) & 0o170000 == 0o120000: - raise ValueError(f"Unsafe archive entry: {path}") - bundle.extractall(unpacked) - roots = [p.parent for p in unpacked.glob("*/index.html")] - if (unpacked / "index.html").exists(): - roots = [unpacked] - if len(roots) != 1: - raise ValueError("Expected exactly one web root") - if not any(roots[0].rglob("*.wasm")) and not any(roots[0].rglob("*.part-*")): - raise ValueError("Missing WebAssembly payload") - # Kubernetes owns the emptyDir root; do not try to chmod that directory. - for source in roots[0].iterdir(): - target = Path("/srv/web") / source.name - if source.is_dir(): - shutil.copytree(source, target, dirs_exist_ok=True) - else: - shutil.copy2(source, target) - print(f"Installed {url}", flush=True) diff --git a/apps/artcraft/files/nginx.conf b/apps/artcraft/files/nginx.conf deleted file mode 100644 index 5a6c383..0000000 --- a/apps/artcraft/files/nginx.conf +++ /dev/null @@ -1,37 +0,0 @@ -worker_processes auto; -pid /tmp/nginx.pid; -error_log /dev/stderr warn; -events { worker_connections 1024; } -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - access_log /dev/stdout; - client_body_temp_path /tmp/client_temp; - proxy_temp_path /tmp/proxy_temp; - fastcgi_temp_path /tmp/fastcgi_temp; - uwsgi_temp_path /tmp/uwsgi_temp; - scgi_temp_path /tmp/scgi_temp; - sendfile on; - gzip on; - gzip_vary on; - gzip_min_length 1024; - gzip_types application/wasm application/javascript text/javascript application/octet-stream text/css application/json; - server { - listen 8080; - root /srv/web; - index index.html; - add_header X-Content-Type-Options nosniff always; - # Some upstream apps use stable filenames. Revalidation prevents stale builds. - add_header Cache-Control no-cache always; - location / { try_files $uri $uri/ =404; } - location ~ /\. { deny all; } - location = /_headers { deny all; } - location = /nginx_status { return 404; } - } - server { - listen 127.0.0.1:8081; - access_log off; - location = /nginx_status { stub_status; } - location / { return 404; } - } -} diff --git a/apps/artcraft/templates/apps.yaml b/apps/artcraft/templates/apps.yaml deleted file mode 100644 index 7b84257..0000000 --- a/apps/artcraft/templates/apps.yaml +++ /dev/null @@ -1,243 +0,0 @@ -{{- range .Values.apps }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .name }} - namespace: {{ $.Release.Namespace }} - labels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft -spec: - replicas: 1 - revisionHistoryLimit: 3 - progressDeadlineSeconds: 900 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - selector: - matchLabels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft - template: - metadata: - labels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft - annotations: - artcraft.brunner.ninja/version: {{ .version | quote }} - spec: - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - fsGroup: 101 - seccompProfile: - type: RuntimeDefault - initContainers: - - name: download-release - image: {{ $.Values.images.downloader }} - command: [python, /config/download.py] - env: - - name: RELEASE_URL - value: {{ .releaseUrl | quote }} - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: [ALL] - resources: - requests: - cpu: 25m - memory: 64Mi - limits: - cpu: "1" - memory: 512Mi - volumeMounts: - - name: web - mountPath: /srv/web - - name: config - mountPath: /config - readOnly: true - - name: tmp - mountPath: /tmp - containers: - - name: nginx - image: {{ $.Values.images.nginx }} - command: [nginx, -g, "daemon off;", -c, /config/nginx.conf] - ports: - - name: http - containerPort: 8080 - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: [ALL] - resources: - requests: - cpu: 10m - memory: 32Mi - limits: - cpu: 500m - memory: 128Mi - startupProbe: - httpGet: - path: /index.html - port: http - periodSeconds: 2 - timeoutSeconds: 2 - failureThreshold: 30 - readinessProbe: - httpGet: - path: /index.html - port: http - periodSeconds: 5 - timeoutSeconds: 2 - failureThreshold: 3 - livenessProbe: - httpGet: - path: /index.html - port: http - periodSeconds: 15 - timeoutSeconds: 2 - failureThreshold: 3 - volumeMounts: - - name: web - mountPath: /srv/web - readOnly: true - - name: config - mountPath: /config - readOnly: true - - name: tmp - mountPath: /tmp - - name: nginx-exporter - image: {{ $.Values.images.exporter }} - args: - - --nginx.scrape-uri=http://127.0.0.1:8081/nginx_status - ports: - - name: metrics - containerPort: 9113 - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: [ALL] - resources: - requests: - cpu: 5m - memory: 16Mi - limits: - cpu: 100m - memory: 64Mi - startupProbe: - httpGet: - path: /metrics - port: metrics - periodSeconds: 2 - timeoutSeconds: 2 - failureThreshold: 30 - readinessProbe: - httpGet: - path: /metrics - port: metrics - periodSeconds: 10 - timeoutSeconds: 2 - failureThreshold: 3 - livenessProbe: - httpGet: - path: /metrics - port: metrics - periodSeconds: 20 - timeoutSeconds: 2 - failureThreshold: 3 - volumes: - - name: web - emptyDir: - sizeLimit: 1Gi - - name: tmp - emptyDir: - sizeLimit: 1Gi - - name: config - configMap: - name: {{ $.Values.configMapName }} - nodeSelector: - odroid-h3: enabled - topologySpreadConstraints: - - maxSkew: 1 - topologyKey: kubernetes.io/hostname - whenUnsatisfiable: DoNotSchedule - nodeTaintsPolicy: Honor - labelSelector: - matchLabels: - app.kubernetes.io/part-of: artcraft ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ .name }} - namespace: {{ $.Release.Namespace }} - labels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft -spec: - selector: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft - ports: - - name: http - port: 80 - targetPort: http - - name: metrics - port: 9113 - targetPort: metrics ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ .name }} - namespace: {{ $.Release.Namespace }} - labels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft - annotations: - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.tls: "true" -spec: - ingressClassName: traefik - tls: - - hosts: - - {{ .host }} - rules: - - host: {{ .host }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ .name }} - port: - name: http ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ .name }} - namespace: {{ $.Release.Namespace }} - labels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft -spec: - selector: - matchLabels: - app.kubernetes.io/name: {{ .name }} - app.kubernetes.io/part-of: artcraft - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s ---- -{{- end }} diff --git a/apps/artcraft/templates/configmap.yaml b/apps/artcraft/templates/configmap.yaml deleted file mode 100644 index 54d0364..0000000 --- a/apps/artcraft/templates/configmap.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Values.configMapName }} - namespace: {{ .Release.Namespace }} -data: - nginx.conf: | -{{ .Files.Get "files/nginx.conf" | indent 4 }} - download.py: | -{{ .Files.Get "files/download.py" | indent 4 }} diff --git a/apps/artcraft/templates/namespace.yaml b/apps/artcraft/templates/namespace.yaml deleted file mode 100644 index 67da829..0000000 --- a/apps/artcraft/templates/namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: {{ .Release.Namespace }} diff --git a/apps/artcraft/values.yaml b/apps/artcraft/values.yaml deleted file mode 100644 index 2d395a5..0000000 --- a/apps/artcraft/values.yaml +++ /dev/null @@ -1,58 +0,0 @@ -configMapName: artcraft-config-4h2gh76d48 -images: - downloader: docker.io/library/python:3.13-alpine - nginx: docker.io/library/nginx:1.30.6-alpine - exporter: docker.io/nginx/nginx-prometheus-exporter:1.5.3 -apps: -- name: cadcraft - version: v0.7.0 - releaseUrl: https://github.com/storytold/cadcraft/releases/download/v0.7.0/cadcraft-web-0.7.0.zip - host: autocad.brunner.ninja -- name: deckcraft - version: v0.7.0 - releaseUrl: https://github.com/storytold/deckcraft/releases/download/v0.7.0/deckcraft-web-0.7.0.zip - host: powerpoint.brunner.ninja -- name: designcraft - version: v0.8.0 - releaseUrl: https://github.com/storytold/designcraft/releases/download/v0.8.0/designcraft-web-0.8.0.zip - host: indesign.brunner.ninja -- name: effectcraft - version: v0.10.0 - releaseUrl: https://github.com/storytold/effectcraft/releases/download/v0.10.0/effectcraft-web-0.10.0.zip - host: aftereffects.brunner.ninja -- name: figcraft - version: v0.6.0 - releaseUrl: https://github.com/storytold/figcraft/releases/download/v0.6.0/figcraft-web-0.6.0.zip - host: figma.brunner.ninja -- name: filmcraft - version: v0.8.0 - releaseUrl: https://github.com/storytold/filmcraft/releases/download/v0.8.0/filmcraft-web-0.8.0.zip - host: premiere.brunner.ninja -- name: gridcraft - version: v0.7.0 - releaseUrl: https://github.com/storytold/gridcraft/releases/download/v0.7.0/gridcraft-web-0.7.0.zip - host: excel.brunner.ninja -- name: lightcraft - version: v0.8.0 - releaseUrl: https://github.com/storytold/lightcraft/releases/download/v0.8.0/lightcraft-web-0.8.0.zip - host: lightroom.brunner.ninja -- name: pdfcraft - version: v0.8.0 - releaseUrl: https://github.com/storytold/pdfcraft/releases/download/v0.8.0/pdfcraft-web-0.8.0.zip - host: acrobat.brunner.ninja -- name: photocraft - version: v0.9.0 - releaseUrl: https://github.com/storytold/photocraft/releases/download/v0.9.0/photocraft-web-0.9.0.zip - host: photoshop.brunner.ninja -- name: soundcraft - version: v0.7.0 - releaseUrl: https://github.com/storytold/soundcraft/releases/download/v0.7.0/soundcraft-web-0.7.0.zip - host: protools.brunner.ninja -- name: vectorcraft - version: v0.12.0 - releaseUrl: https://github.com/storytold/vectorcraft/releases/download/v0.12.0/vectorcraft-web-0.12.0.zip - host: illustrator.brunner.ninja -- name: wordcraft - version: v0.7.0 - releaseUrl: https://github.com/storytold/wordcraft/releases/download/v0.7.0/wordcraft-web-0.7.0.zip - host: word.brunner.ninja diff --git a/bootstrap/artcraft-project.yaml b/bootstrap/artcraft-project.yaml index 99e12c0..bc094ad 100644 --- a/bootstrap/artcraft-project.yaml +++ b/bootstrap/artcraft-project.yaml @@ -7,6 +7,7 @@ spec: description: Stateless Artcraft web applications sourceRepos: - https://code.brunner.ninja/feedc0de/homelab-gitops.git + - https://brunner.ninja/charts destinations: - namespace: artcraft server: https://kubernetes.default.svc diff --git a/bootstrap/artcraft.yaml b/bootstrap/artcraft.yaml deleted file mode 100644 index aaa1f9c..0000000 --- a/bootstrap/artcraft.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: artcraft - namespace: argocd -spec: - project: artcraft - source: - repoURL: https://code.brunner.ninja/feedc0de/homelab-gitops.git - targetRevision: main - path: apps/artcraft - helm: - releaseName: artcraft - destination: - server: https://kubernetes.default.svc - namespace: artcraft - syncPolicy: - automated: - enabled: true - prune: true - selfHeal: true diff --git a/bootstrap/kustomization.yaml b/bootstrap/kustomization.yaml index e8b7158..d9422ee 100644 --- a/bootstrap/kustomization.yaml +++ b/bootstrap/kustomization.yaml @@ -17,7 +17,19 @@ resources: - watschn-studio.yaml - artcraft-project.yaml - coturn-project.yaml -- artcraft.yaml +- cadcraft.yaml +- deckcraft.yaml +- designcraft.yaml +- effectcraft.yaml +- figcraft.yaml +- filmcraft.yaml +- gridcraft.yaml +- lightcraft.yaml +- pdfcraft.yaml +- photocraft.yaml +- soundcraft.yaml +- vectorcraft.yaml +- wordcraft.yaml - brunner-ninja.yaml - coturn.yaml - flaresolverr.yaml