initial commit
All checks were successful
Build and Push Image / build-and-push (push) Successful in 1m26s

This commit is contained in:
Michael Trip 2026-01-09 21:58:53 +01:00
parent 3bba1f6db6
commit b56e866071
36 changed files with 4160 additions and 0 deletions

27
k8s/configmap.yaml Normal file
View file

@ -0,0 +1,27 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: snauw-counter-config
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: config
data:
FLASK_ENV: "production"
DATABASE_URL: "sqlite:///app/data/snauw_counter.db"
SECRET_KEY_FILE: "/etc/secrets/secret-key"
PROMETHEUS_MULTIPROC_DIR: "/tmp/prometheus"
---
apiVersion: v1
kind: Secret
metadata:
name: snauw-counter-secrets
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: config
type: Opaque
data:
# Generate with: openssl rand -base64 32 | base64 -w 0
secret-key: "" # Add your base64 encoded secret key

123
k8s/deployment.yaml Normal file
View file

@ -0,0 +1,123 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: snauw-counter
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
app.kubernetes.io/part-of: snauw-counter
app.kubernetes.io/version: ${IMAGE_TAG:-latest}
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
template:
metadata:
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
app.kubernetes.io/part-of: snauw-counter
app.kubernetes.io/version: ${IMAGE_TAG:-latest}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "5000"
prometheus.io/path: "/metrics"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
initContainers:
- name: init-sqlite
image: busybox:1.35
command: ['sh', '-c', 'mkdir -p /app/data && chown -R 1001:1001 /app/data']
volumeMounts:
- name: sqlite-data
mountPath: /app/data
securityContext:
runAsUser: 0 # Run as root for chown
containers:
- name: snauw-counter
image: ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG:-latest}
ports:
- containerPort: 5000
name: http
protocol: TCP
env:
- name: FLASK_ENV
valueFrom:
configMapKeyRef:
name: snauw-counter-config
key: FLASK_ENV
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: snauw-counter-config
key: DATABASE_URL
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: snauw-counter-secrets
key: secret-key
- name: PROMETHEUS_MULTIPROC_DIR
valueFrom:
configMapKeyRef:
name: snauw-counter-config
key: PROMETHEUS_MULTIPROC_DIR
volumeMounts:
- name: secrets
mountPath: /etc/secrets
readOnly: true
- name: tmp
mountPath: /tmp
- name: sqlite-data
mountPath: /app/data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALL
volumes:
- name: secrets
secret:
secretName: snauw-counter-secrets
defaultMode: 0400
- name: tmp
emptyDir: {}
- name: sqlite-data
persistentVolumeClaim:
claimName: snauw-counter-sqlite-pvc
imagePullSecrets:
- name: ghcr-secret

33
k8s/ingress.yaml Normal file
View file

@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: snauw-counter
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
app.kubernetes.io/part-of: snauw-counter
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
spec:
ingressClassName: nginx
tls:
- hosts:
- snauw-counter.yourdomain.com
secretName: snauw-counter-tls
rules:
- host: snauw-counter.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: snauw-counter
port:
number: 80

8
k8s/namespace.yaml Normal file
View file

@ -0,0 +1,8 @@
apiVersion: v1
kind: Namespace
metadata:
name: snauw-counter
labels:
name: snauw-counter
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/part-of: snauw-counter

96
k8s/postgres.yaml Normal file
View file

@ -0,0 +1,96 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: snauw-counter
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: snauw-counter
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: postgres
template:
metadata:
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: snauw-counter
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_DB
value: snauw_counter
- name: POSTGRES_USER
value: snauw_user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: snauw-counter-secrets
key: postgres-password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
exec:
command:
- pg_isready
- -U
- snauw_user
- -d
- snauw_counter
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- pg_isready
- -U
- snauw_user
- -d
- snauw_counter
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: postgres-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: snauw-counter
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: snauw-counter
spec:
ports:
- port: 5432
targetPort: 5432
name: postgres
selector:
app.kubernetes.io/name: postgres

59
k8s/scaling.yaml Normal file
View file

@ -0,0 +1,59 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: snauw-counter-pdb
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
app.kubernetes.io/part-of: snauw-counter
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: snauw-counter-hpa
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
app.kubernetes.io/part-of: snauw-counter
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: snauw-counter
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 60

23
k8s/service.yaml Normal file
View file

@ -0,0 +1,23 @@
apiVersion: v1
kind: Service
metadata:
name: snauw-counter
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web
app.kubernetes.io/part-of: snauw-counter
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "5000"
prometheus.io/path: "/metrics"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: web

16
k8s/sqlite-pvc.yaml Normal file
View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: snauw-counter-sqlite-pvc
namespace: snauw-counter
labels:
app.kubernetes.io/name: snauw-counter
app.kubernetes.io/component: database
app.kubernetes.io/part-of: snauw-counter
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: default