Add Dockerfile, K8s manifests, and ArgoCD app for OpenShift deployment
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
node_modules/\nserver.log
|
node_modules/
|
||||||
|
server.log
|
||||||
|
|||||||
11
Dockerfile
Normal file
11
Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
FROM node:22-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --omit=dev
|
||||||
|
COPY server.js ./
|
||||||
|
COPY public/ ./public/
|
||||||
|
RUN mkdir -p /app/data && chgrp -R 0 /app && chmod -R g=u /app
|
||||||
|
ENV DATA_DIR=/app/data
|
||||||
|
EXPOSE 3333
|
||||||
|
USER 1001
|
||||||
|
CMD ["node", "server.js"]
|
||||||
20
bootstrap/argo-app.yaml
Normal file
20
bootstrap/argo-app.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
|
namespace: openshift-gitops
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://gitea.apilab.us/cscott/priority-horizon
|
||||||
|
targetRevision: main
|
||||||
|
path: manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: clawrizon
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=false
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
{
|
{
|
||||||
"id": 10,
|
"id": 10,
|
||||||
"column": "now",
|
"column": "now",
|
||||||
"text": "Clawd: Add service/route for this (git first)",
|
"text": "✅ Clawd: Git + Gitea done. Route next?",
|
||||||
"order": 3
|
"order": 3
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
21
manifests/buildconfig.yaml
Normal file
21
manifests/buildconfig.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: build.openshift.io/v1
|
||||||
|
kind: BuildConfig
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
|
namespace: clawrizon
|
||||||
|
spec:
|
||||||
|
source:
|
||||||
|
type: Git
|
||||||
|
git:
|
||||||
|
uri: https://gitea.apilab.us/cscott/priority-horizon
|
||||||
|
ref: main
|
||||||
|
strategy:
|
||||||
|
type: Docker
|
||||||
|
dockerStrategy:
|
||||||
|
dockerfilePath: Dockerfile
|
||||||
|
output:
|
||||||
|
to:
|
||||||
|
kind: ImageStreamTag
|
||||||
|
name: clawrizon:latest
|
||||||
|
triggers:
|
||||||
|
- type: ConfigChange
|
||||||
47
manifests/deployment.yaml
Normal file
47
manifests/deployment.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
|
namespace: clawrizon
|
||||||
|
labels:
|
||||||
|
app: clawrizon
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: clawrizon
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: clawrizon
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: clawrizon
|
||||||
|
image: image-registry.openshift-image-registry.svc:5000/clawrizon/clawrizon:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 3333
|
||||||
|
env:
|
||||||
|
- name: DATA_DIR
|
||||||
|
value: /app/data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /app/data
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: clawrizon-data
|
||||||
5
manifests/imagestream.yaml
Normal file
5
manifests/imagestream.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: image.openshift.io/v1
|
||||||
|
kind: ImageStream
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
|
namespace: clawrizon
|
||||||
4
manifests/namespace.yaml
Normal file
4
manifests/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
12
manifests/pvc.yaml
Normal file
12
manifests/pvc.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: clawrizon-data
|
||||||
|
namespace: clawrizon
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: local-nvme-retain
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
16
manifests/route.yaml
Normal file
16
manifests/route.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: route.openshift.io/v1
|
||||||
|
kind: Route
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
|
namespace: clawrizon
|
||||||
|
spec:
|
||||||
|
host: clawrizon.apps.lab.apilab.us
|
||||||
|
to:
|
||||||
|
kind: Service
|
||||||
|
name: clawrizon
|
||||||
|
weight: 100
|
||||||
|
port:
|
||||||
|
targetPort: 3333
|
||||||
|
tls:
|
||||||
|
termination: edge
|
||||||
|
insecureEdgeTerminationPolicy: Redirect
|
||||||
12
manifests/service.yaml
Normal file
12
manifests/service.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: clawrizon
|
||||||
|
namespace: clawrizon
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: clawrizon
|
||||||
|
ports:
|
||||||
|
- port: 3333
|
||||||
|
targetPort: 3333
|
||||||
|
protocol: TCP
|
||||||
13
server.js
13
server.js
@@ -3,7 +3,14 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const DATA_FILE = path.join(__dirname, 'data.json');
|
const DATA_DIR = process.env.DATA_DIR || __dirname;
|
||||||
|
const DATA_FILE = path.join(DATA_DIR, 'data.json');
|
||||||
|
|
||||||
|
// Seed data.json if it does not exist
|
||||||
|
if (!fs.existsSync(DATA_FILE)) {
|
||||||
|
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||||
|
fs.writeFileSync(DATA_FILE, JSON.stringify({ notes: [], nextId: 1 }, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.static(path.join(__dirname, 'public')));
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
@@ -42,7 +49,6 @@ app.patch('/api/notes/:id', (req, res) => {
|
|||||||
if (req.body.column !== undefined) note.column = req.body.column;
|
if (req.body.column !== undefined) note.column = req.body.column;
|
||||||
if (req.body.order !== undefined) note.order = req.body.order;
|
if (req.body.order !== undefined) note.order = req.body.order;
|
||||||
if (req.body.reorder) {
|
if (req.body.reorder) {
|
||||||
// reorder: [{id, order}, ...]
|
|
||||||
req.body.reorder.forEach(r => {
|
req.body.reorder.forEach(r => {
|
||||||
const n = data.notes.find(x => x.id === r.id);
|
const n = data.notes.find(x => x.id === r.id);
|
||||||
if (n) { n.order = r.order; if (r.column) n.column = r.column; }
|
if (n) { n.order = r.order; if (r.column) n.column = r.column; }
|
||||||
@@ -61,10 +67,9 @@ app.delete('/api/notes/:id', (req, res) => {
|
|||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bulk reorder endpoint
|
|
||||||
app.put('/api/reorder', (req, res) => {
|
app.put('/api/reorder', (req, res) => {
|
||||||
const data = readData();
|
const data = readData();
|
||||||
const { items } = req.body; // [{id, column, order}]
|
const { items } = req.body;
|
||||||
if (!items) return res.status(400).json({ error: 'items required' });
|
if (!items) return res.status(400).json({ error: 'items required' });
|
||||||
items.forEach(r => {
|
items.forEach(r => {
|
||||||
const n = data.notes.find(x => x.id === r.id);
|
const n = data.notes.find(x => x.id === r.id);
|
||||||
|
|||||||
Reference in New Issue
Block a user