Initial commit: Essential Oil Formula Cost Calculator
This commit is contained in:
39
deploy/backup-cronjob.yaml
Normal file
39
deploy/backup-cronjob.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: hourly-backup
|
||||
namespace: oil-calculator
|
||||
spec:
|
||||
schedule: "0 * * * *" # Every hour
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 2
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: backup
|
||||
image: registry.oci.euphon.net/oil-calculator:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
BACKUP_DIR=/data/backups
|
||||
mkdir -p $BACKUP_DIR
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
# Backup SQLite database using .backup for consistency
|
||||
sqlite3 /data/oil_calculator.db ".backup '$BACKUP_DIR/oil_calculator_${DATE}.db'"
|
||||
echo "Backup done: $BACKUP_DIR/oil_calculator_${DATE}.db ($(du -h $BACKUP_DIR/oil_calculator_${DATE}.db | cut -f1))"
|
||||
# Keep last 48 backups (2 days of hourly)
|
||||
ls -t $BACKUP_DIR/oil_calculator_*.db | tail -n +49 | xargs rm -f 2>/dev/null
|
||||
echo "Backups retained: $(ls $BACKUP_DIR/oil_calculator_*.db | wc -l)"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: oil-calculator-data
|
||||
restartPolicy: OnFailure
|
||||
imagePullSecrets:
|
||||
- name: regcred
|
||||
30
deploy/cronjob.yaml
Normal file
30
deploy/cronjob.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: weekly-review
|
||||
namespace: oil-calculator
|
||||
spec:
|
||||
schedule: "0 9 * * 1" # Every Monday 9:00 UTC (17:00 China time)
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: cron
|
||||
image: curlimages/curl:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
curl -sf -X POST \
|
||||
-H "Authorization: Bearer $(ADMIN_TOKEN)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}' \
|
||||
http://oil-calculator.oil-calculator.svc/api/cron/weekly-review
|
||||
env:
|
||||
- name: ADMIN_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: oil-calculator-secrets
|
||||
key: admin-token
|
||||
restartPolicy: OnFailure
|
||||
47
deploy/deployment.yaml
Normal file
47
deploy/deployment.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: oil-calculator
|
||||
namespace: oil-calculator
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: oil-calculator
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: oil-calculator
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: regcred
|
||||
containers:
|
||||
- name: oil-calculator
|
||||
image: registry.oci.euphon.net/oil-calculator:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: DB_PATH
|
||||
value: /data/oil_calculator.db
|
||||
- name: FRONTEND_DIR
|
||||
value: /app/frontend
|
||||
- name: ADMIN_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: oil-calculator-secrets
|
||||
key: admin-token
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: oil-calculator-data
|
||||
23
deploy/ingress.yaml
Normal file
23
deploy/ingress.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: oil-calculator
|
||||
namespace: oil-calculator
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.tls.certresolver: le
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: oil.oci.euphon.net
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: oil-calculator
|
||||
port:
|
||||
number: 80
|
||||
tls:
|
||||
- hosts:
|
||||
- oil.oci.euphon.net
|
||||
4
deploy/namespace.yaml
Normal file
4
deploy/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: oil-calculator
|
||||
11
deploy/pvc.yaml
Normal file
11
deploy/pvc.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: oil-calculator-data
|
||||
namespace: oil-calculator
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
11
deploy/service.yaml
Normal file
11
deploy/service.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: oil-calculator
|
||||
namespace: oil-calculator
|
||||
spec:
|
||||
selector:
|
||||
app: oil-calculator
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8000
|
||||
82
deploy/setup-kubeconfig.sh
Normal file
82
deploy/setup-kubeconfig.sh
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
# Creates a restricted kubeconfig for the oil-calculator namespace only.
|
||||
# Run on the k8s server as a user with cluster-admin access.
|
||||
set -e
|
||||
|
||||
NAMESPACE=oil-calculator
|
||||
SA_NAME=oil-calculator-deployer
|
||||
|
||||
echo "Creating ServiceAccount, Role, and RoleBinding..."
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: ${SA_NAME}
|
||||
namespace: ${NAMESPACE}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: ${SA_NAME}-role
|
||||
namespace: ${NAMESPACE}
|
||||
rules:
|
||||
- apiGroups: ["", "apps", "networking.k8s.io"]
|
||||
resources: ["pods", "services", "deployments", "replicasets", "ingresses", "persistentvolumeclaims", "configmaps", "secrets", "pods/log"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: ${SA_NAME}-binding
|
||||
namespace: ${NAMESPACE}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: ${SA_NAME}
|
||||
namespace: ${NAMESPACE}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: ${SA_NAME}-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ${SA_NAME}-token
|
||||
namespace: ${NAMESPACE}
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: ${SA_NAME}
|
||||
type: kubernetes.io/service-account-token
|
||||
EOF
|
||||
|
||||
echo "Waiting for token..."
|
||||
sleep 3
|
||||
|
||||
# Get cluster info
|
||||
CLUSTER_SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
|
||||
CLUSTER_CA=$(kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')
|
||||
TOKEN=$(kubectl get secret ${SA_NAME}-token -n ${NAMESPACE} -o jsonpath='{.data.token}' | base64 -d)
|
||||
|
||||
cat > kubeconfig <<EOF
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: ${CLUSTER_CA}
|
||||
server: ${CLUSTER_SERVER}
|
||||
name: oil-calculator
|
||||
contexts:
|
||||
- context:
|
||||
cluster: oil-calculator
|
||||
namespace: ${NAMESPACE}
|
||||
user: ${SA_NAME}
|
||||
name: oil-calculator
|
||||
current-context: oil-calculator
|
||||
users:
|
||||
- name: ${SA_NAME}
|
||||
user:
|
||||
token: ${TOKEN}
|
||||
EOF
|
||||
|
||||
echo "Kubeconfig written to ./kubeconfig"
|
||||
echo "Test with: KUBECONFIG=./kubeconfig kubectl get pods"
|
||||
Reference in New Issue
Block a user