Deploy JobSync — job search tracker on ringtail k3s (#288)
All checks were successful
Build Container (Nix) / detect (push) Successful in 1s
Build Container / detect (push) Successful in 2s
Build Container / build (jobsync) (push) Successful in 2s
Build Container (Nix) / build (jobsync) (push) Successful in 8s

## Summary

C2 Mikado chain to deploy [JobSync](https://github.com/Gsync/jobsync) — a self-hosted job application tracker — to ringtail's k3s cluster.

### Mikado Graph

```
deploy-jobsync (goal)
├── build-jobsync-container
│   └── mirror-jobsync
└── integrate-jobsync-ollama
```

### What is JobSync?

Next.js app with SQLite for tracking job applications. Features resume management, application pipeline tracking, and AI-powered resume review/job matching.

### Key Decisions

- **Ringtail k3s** (not minikube-indri) — colocates with Ollama for zero-latency AI
- **Nix container** via `buildLayeredImage` — no Dockerfile, mirrors upstream source on forge
- **Ollama for AI** — uses existing deployment, no API keys needed for AI features
- **No upstream fork** — vanilla JobSync, Anthropic AI deferred to future work if needed

### Current Status

Planning phase — cards committed, ready for review before implementation begins.

Reviewed-on: #288
This commit is contained in:
Erich Blume 2026-03-08 11:02:05 -07:00
commit 3a811fb188
15 changed files with 459 additions and 0 deletions

18
argocd/apps/jobsync.yaml Normal file
View file

@ -0,0 +1,18 @@
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: jobsync
namespace: argocd
spec:
project: default
source:
repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
targetRevision: main
path: argocd/manifests/jobsync
destination:
server: https://ringtail.tail8d86e.ts.net:6443
namespace: jobsync
syncPolicy:
syncOptions:
- CreateNamespace=true

View file

@ -0,0 +1,73 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jobsync
namespace: jobsync
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: jobsync
template:
metadata:
labels:
app: jobsync
spec:
containers:
- name: jobsync
image: blumeops/jobsync:kustomized
ports:
- containerPort: 3000
name: http
env:
- name: DATABASE_URL
value: "file:/data/dev.db"
- name: NEXTAUTH_URL
value: "https://jobsync.ops.eblu.me"
- name: AUTH_TRUST_HOST
value: "true"
- name: NEXT_TELEMETRY_DISABLED
value: "1"
- name: TZ
value: "America/Los_Angeles"
- name: OLLAMA_BASE_URL
value: "http://ollama.ollama.svc.cluster.local:11434"
- name: AUTH_SECRET
valueFrom:
secretKeyRef:
name: jobsync-secrets
key: auth_secret
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: jobsync-secrets
key: encryption_key
volumeMounts:
- name: data
mountPath: /data
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 10
periodSeconds: 10
volumes:
- name: data
persistentVolumeClaim:
claimName: jobsync-data

View file

@ -0,0 +1,23 @@
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: jobsync-secrets
namespace: jobsync
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: jobsync-secrets
creationPolicy: Owner
data:
- secretKey: auth_secret
remoteRef:
key: JobSync
property: auth_secret
- secretKey: encryption_key
remoteRef:
key: JobSync
property: encryption_key

View file

@ -0,0 +1,26 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jobsync-tailscale
namespace: jobsync
annotations:
tailscale.com/proxy-class: "default"
tailscale.com/proxy-group: "ingress"
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "JobSync"
gethomepage.dev/group: "Apps"
gethomepage.dev/icon: "mdi-briefcase-search"
gethomepage.dev/description: "Job application tracker"
gethomepage.dev/href: "https://jobsync.ops.eblu.me"
gethomepage.dev/pod-selector: "app=jobsync"
spec:
ingressClassName: tailscale
defaultBackend:
service:
name: jobsync
port:
number: 3000
tls:
- hosts:
- jobsync

View file

@ -0,0 +1,15 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: jobsync
resources:
- pvc.yaml
- external-secret.yaml
- deployment.yaml
- service.yaml
- ingress-tailscale.yaml
images:
- name: blumeops/jobsync
newName: registry.ops.eblu.me/blumeops/jobsync
newTag: "v1.1.4-e51ec83-nix"

View file

@ -0,0 +1,13 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jobsync-data
namespace: jobsync
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 5Gi

View file

@ -0,0 +1,13 @@
---
apiVersion: v1
kind: Service
metadata:
name: jobsync
namespace: jobsync
spec:
selector:
app: jobsync
ports:
- name: http
port: 3000
targetPort: 3000