feat(notesnook): migrate self-hosted Notesnook to k3s
Adds apps/notesnook (namespace, config, mongo rs0 StatefulSet, minio, identity/sync/sse/monograph deployments + Traefik/cert-manager ingresses) and argocd/notesnook.yaml. Secret applied out-of-band (only .example committed). Includes design spec + implementation plan under docs/superpowers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: notesnook-attachments
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: attachments.notes.aleshym.co
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: notesnook-s3
|
||||
port: { number: 9000 }
|
||||
tls:
|
||||
- hosts: ["attachments.notes.aleshym.co"]
|
||||
secretName: notesnook-attachments-tls
|
||||
@@ -0,0 +1,27 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: notesnook-db-init
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: PostSync
|
||||
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
|
||||
spec:
|
||||
backoffLimit: 20
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: rs-init
|
||||
image: mongo:7.0.12
|
||||
command: ["bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
until mongosh mongodb://notesnook-db:27017 --quiet --eval 'db.runCommand("ping").ok' ; do
|
||||
echo "waiting for mongod..."; sleep 3;
|
||||
done
|
||||
mongosh mongodb://notesnook-db:27017 --quiet --eval '
|
||||
try { rs.status() }
|
||||
catch (e) { rs.initiate({_id:"rs0", members:[{_id:0, host:"notesnook-db:27017"}]}) }
|
||||
'
|
||||
echo "replica set ready"
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notesnook-db
|
||||
namespace: notesnook
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: notesnook-db
|
||||
ports:
|
||||
- name: mongo
|
||||
port: 27017
|
||||
targetPort: 27017
|
||||
@@ -0,0 +1,42 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: notesnook-db
|
||||
namespace: notesnook
|
||||
spec:
|
||||
serviceName: notesnook-db
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: notesnook-db
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: notesnook-db
|
||||
spec:
|
||||
containers:
|
||||
- name: mongod
|
||||
image: mongo:7.0.12
|
||||
args: ["--replSet", "rs0", "--bind_ip_all"]
|
||||
ports:
|
||||
- containerPort: 27017
|
||||
name: mongo
|
||||
volumeMounts:
|
||||
- name: dbdata
|
||||
mountPath: /data/db
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["mongosh", "--quiet", "--eval", "db.runCommand('ping').ok"]
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
resources:
|
||||
requests: { cpu: "100m", memory: "256Mi" }
|
||||
limits: { cpu: "1000m", memory: "1Gi" }
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: dbdata
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -0,0 +1,39 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: notesnook-identity
|
||||
namespace: notesnook
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: notesnook-identity
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: notesnook-identity
|
||||
spec:
|
||||
containers:
|
||||
- name: identity
|
||||
image: streetwriters/identity:latest
|
||||
envFrom:
|
||||
- configMapRef: { name: notesnook-config }
|
||||
- secretRef: { name: notesnook-secret }
|
||||
env:
|
||||
- name: MONGODB_CONNECTION_STRING
|
||||
value: "mongodb://notesnook-db:27017/identity?replSet=rs0"
|
||||
- name: MONGODB_DATABASE_NAME
|
||||
value: "identity"
|
||||
ports:
|
||||
- { containerPort: 8264, name: http }
|
||||
readinessProbe:
|
||||
httpGet: { path: /health, port: 8264 }
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
livenessProbe:
|
||||
httpGet: { path: /health, port: 8264 }
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
resources:
|
||||
requests: { cpu: "50m", memory: "128Mi" }
|
||||
limits: { cpu: "500m", memory: "512Mi" }
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: notesnook-auth
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: auth.notes.aleshym.co
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: notesnook-identity
|
||||
port: { name: http }
|
||||
tls:
|
||||
- hosts: ["auth.notes.aleshym.co"]
|
||||
secretName: notesnook-auth-tls
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notesnook-identity
|
||||
namespace: notesnook
|
||||
spec:
|
||||
selector:
|
||||
app: notesnook-identity
|
||||
ports:
|
||||
- { name: http, port: 8264, targetPort: 8264 }
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: notesnook
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- notesnook-config.yaml
|
||||
- db-service.yaml
|
||||
- db-statefulset.yaml
|
||||
- db-init-job.yaml
|
||||
- minio-pvc.yaml
|
||||
- minio-deployment.yaml
|
||||
- minio-service.yaml
|
||||
- minio-bucket-job.yaml
|
||||
- identity-deployment.yaml
|
||||
- identity-service.yaml
|
||||
- identity-ingress.yaml
|
||||
- sync-deployment.yaml
|
||||
- sync-service.yaml
|
||||
- sync-ingress.yaml
|
||||
- sse-deployment.yaml
|
||||
- sse-service.yaml
|
||||
- sse-ingress.yaml
|
||||
- monograph-deployment.yaml
|
||||
- monograph-service.yaml
|
||||
- monograph-ingress.yaml
|
||||
- attachments-ingress.yaml
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: notesnook-s3-setup
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: PostSync
|
||||
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
|
||||
spec:
|
||||
backoffLimit: 20
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: mc
|
||||
image: minio/mc:RELEASE.2024-07-26T13-08-44Z
|
||||
envFrom:
|
||||
- secretRef: { name: notesnook-secret }
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
until mc alias set minio http://notesnook-s3:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"; do
|
||||
sleep 2;
|
||||
done
|
||||
mc mb --ignore-existing minio/attachments
|
||||
echo "bucket ready"
|
||||
@@ -0,0 +1,42 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: notesnook-s3
|
||||
namespace: notesnook
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy: { type: Recreate }
|
||||
selector:
|
||||
matchLabels:
|
||||
app: notesnook-s3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: notesnook-s3
|
||||
spec:
|
||||
containers:
|
||||
- name: minio
|
||||
image: minio/minio:RELEASE.2024-07-29T22-14-52Z
|
||||
args: ["server", "/data/s3", "--console-address", ":9090"]
|
||||
envFrom:
|
||||
- secretRef: { name: notesnook-secret }
|
||||
env:
|
||||
- name: MINIO_BROWSER
|
||||
value: "on"
|
||||
ports:
|
||||
- { containerPort: 9000, name: api }
|
||||
- { containerPort: 9090, name: console }
|
||||
volumeMounts:
|
||||
- name: s3data
|
||||
mountPath: /data/s3
|
||||
readinessProbe:
|
||||
tcpSocket: { port: 9000 }
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
resources:
|
||||
requests: { cpu: "50m", memory: "128Mi" }
|
||||
limits: { cpu: "500m", memory: "512Mi" }
|
||||
volumes:
|
||||
- name: s3data
|
||||
persistentVolumeClaim:
|
||||
claimName: notesnook-s3-data
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: notesnook-s3-data
|
||||
namespace: notesnook
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notesnook-s3
|
||||
namespace: notesnook
|
||||
spec:
|
||||
selector:
|
||||
app: notesnook-s3
|
||||
ports:
|
||||
- { name: api, port: 9000, targetPort: 9000 }
|
||||
- { name: console, port: 9090, targetPort: 9090 }
|
||||
@@ -0,0 +1,37 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: notesnook-monograph
|
||||
namespace: notesnook
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: notesnook-monograph
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: notesnook-monograph
|
||||
spec:
|
||||
containers:
|
||||
- name: monograph
|
||||
image: streetwriters/monograph:latest
|
||||
envFrom:
|
||||
- configMapRef: { name: notesnook-config }
|
||||
- secretRef: { name: notesnook-secret }
|
||||
env:
|
||||
- name: HOST
|
||||
value: "0.0.0.0"
|
||||
- name: API_HOST
|
||||
value: "http://notesnook-sync:5264"
|
||||
- name: PUBLIC_URL
|
||||
value: "https://monograph.notes.aleshym.co"
|
||||
ports:
|
||||
- { containerPort: 3000, name: http }
|
||||
readinessProbe:
|
||||
httpGet: { path: /, port: 3000 }
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
resources:
|
||||
requests: { cpu: "50m", memory: "128Mi" }
|
||||
limits: { cpu: "500m", memory: "512Mi" }
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: notesnook-monograph
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: monograph.notes.aleshym.co
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: { name: notesnook-monograph, port: { name: http } }
|
||||
tls:
|
||||
- hosts: ["monograph.notes.aleshym.co"]
|
||||
secretName: notesnook-monograph-tls
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notesnook-monograph
|
||||
namespace: notesnook
|
||||
spec:
|
||||
selector:
|
||||
app: notesnook-monograph
|
||||
ports:
|
||||
- { name: http, port: 3000, targetPort: 3000 }
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: notesnook
|
||||
@@ -0,0 +1,29 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: notesnook-config
|
||||
namespace: notesnook
|
||||
data:
|
||||
INSTANCE_NAME: "aleshym-notesnook"
|
||||
DISABLE_SIGNUPS: "true"
|
||||
NOTESNOOK_APP_PUBLIC_URL: "https://app.notesnook.com"
|
||||
AUTH_SERVER_PUBLIC_URL: "https://auth.notes.aleshym.co"
|
||||
MONOGRAPH_PUBLIC_URL: "https://monograph.notes.aleshym.co"
|
||||
ATTACHMENTS_SERVER_PUBLIC_URL: "https://attachments.notes.aleshym.co"
|
||||
NOTESNOOK_CORS_ORIGINS: "https://app.notesnook.com,https://notes.aleshym.co"
|
||||
KNOWN_PROXIES: ""
|
||||
SELF_HOSTED: "1"
|
||||
NOTESNOOK_SERVER_HOST: "notesnook-sync"
|
||||
NOTESNOOK_SERVER_PORT: "5264"
|
||||
IDENTITY_SERVER_HOST: "notesnook-identity"
|
||||
IDENTITY_SERVER_PORT: "8264"
|
||||
SSE_SERVER_HOST: "notesnook-sse"
|
||||
SSE_SERVER_PORT: "7264"
|
||||
IDENTITY_SERVER_URL: "https://auth.notes.aleshym.co"
|
||||
NOTESNOOK_APP_HOST: "https://app.notesnook.com"
|
||||
S3_INTERNAL_SERVICE_URL: "http://notesnook-s3:9000"
|
||||
S3_INTERNAL_BUCKET_NAME: "attachments"
|
||||
S3_SERVICE_URL: "https://attachments.notes.aleshym.co"
|
||||
S3_BUCKET_NAME: "attachments"
|
||||
S3_REGION: "us-east-1"
|
||||
MINIO_BROWSER: "on"
|
||||
@@ -0,0 +1,19 @@
|
||||
# DO NOT COMMIT THE REAL VERSION. Copy to notesnook-secret.yaml (gitignored),
|
||||
# fill real values from the old stack's .env, then:
|
||||
# kubectl apply -f apps/notesnook/notesnook-secret.yaml
|
||||
# ArgoCD ignores this Secret's /data (see argocd/notesnook.yaml).
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: notesnook-secret
|
||||
namespace: notesnook
|
||||
stringData:
|
||||
NOTESNOOK_API_SECRET: "CHANGE_ME"
|
||||
SMTP_USERNAME: "funman300@gmail.com"
|
||||
SMTP_PASSWORD: "CHANGE_ME"
|
||||
SMTP_HOST: "smtp.gmail.com"
|
||||
SMTP_PORT: "587"
|
||||
MINIO_ROOT_USER: "notesnook"
|
||||
MINIO_ROOT_PASSWORD: "CHANGE_ME"
|
||||
S3_ACCESS_KEY_ID: "notesnook"
|
||||
S3_ACCESS_KEY: "CHANGE_ME"
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: notesnook-sse
|
||||
namespace: notesnook
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: notesnook-sse
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: notesnook-sse
|
||||
spec:
|
||||
containers:
|
||||
- name: sse
|
||||
image: streetwriters/sse:latest
|
||||
envFrom:
|
||||
- configMapRef: { name: notesnook-config }
|
||||
- secretRef: { name: notesnook-secret }
|
||||
ports:
|
||||
- { containerPort: 7264, name: http }
|
||||
readinessProbe:
|
||||
httpGet: { path: /health, port: 7264 }
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
livenessProbe:
|
||||
httpGet: { path: /health, port: 7264 }
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
resources:
|
||||
requests: { cpu: "50m", memory: "128Mi" }
|
||||
limits: { cpu: "500m", memory: "256Mi" }
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: notesnook-sse
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: events.notes.aleshym.co
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: { name: notesnook-sse, port: { name: http } }
|
||||
tls:
|
||||
- hosts: ["events.notes.aleshym.co"]
|
||||
secretName: notesnook-sse-tls
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notesnook-sse
|
||||
namespace: notesnook
|
||||
spec:
|
||||
selector:
|
||||
app: notesnook-sse
|
||||
ports:
|
||||
- { name: http, port: 7264, targetPort: 7264 }
|
||||
@@ -0,0 +1,39 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: notesnook-sync
|
||||
namespace: notesnook
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: notesnook-sync
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: notesnook-sync
|
||||
spec:
|
||||
containers:
|
||||
- name: sync
|
||||
image: streetwriters/notesnook-sync:latest
|
||||
envFrom:
|
||||
- configMapRef: { name: notesnook-config }
|
||||
- secretRef: { name: notesnook-secret }
|
||||
env:
|
||||
- name: MONGODB_CONNECTION_STRING
|
||||
value: "mongodb://notesnook-db:27017/?replSet=rs0"
|
||||
- name: MONGODB_DATABASE_NAME
|
||||
value: "notesnook"
|
||||
ports:
|
||||
- { containerPort: 5264, name: http }
|
||||
readinessProbe:
|
||||
httpGet: { path: /health, port: 5264 }
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
livenessProbe:
|
||||
httpGet: { path: /health, port: 5264 }
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
resources:
|
||||
requests: { cpu: "50m", memory: "128Mi" }
|
||||
limits: { cpu: "1000m", memory: "512Mi" }
|
||||
@@ -0,0 +1,28 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: notesnook-sync
|
||||
namespace: notesnook
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: sync.notes.aleshym.co
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: { name: notesnook-sync, port: { name: http } }
|
||||
- host: notes.aleshym.co
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: { name: notesnook-sync, port: { name: http } }
|
||||
tls:
|
||||
- hosts: ["sync.notes.aleshym.co", "notes.aleshym.co"]
|
||||
secretName: notesnook-sync-tls
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notesnook-sync
|
||||
namespace: notesnook
|
||||
spec:
|
||||
selector:
|
||||
app: notesnook-sync
|
||||
ports:
|
||||
- { name: http, port: 5264, targetPort: 5264 }
|
||||
Reference in New Issue
Block a user