diff --git a/.gitea/workflows/build-push.yaml b/.gitea/workflows/build-push.yaml index 06d396a..67b3ccc 100644 --- a/.gitea/workflows/build-push.yaml +++ b/.gitea/workflows/build-push.yaml @@ -3,7 +3,7 @@ name: Build and Push Container Image on: push: branches: - - master + - main paths-ignore: - "deploy/**" env: diff --git a/deploy/.gitkeep b/deploy/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/deploy/base/cert.yaml b/deploy/base/cert.yaml new file mode 100644 index 0000000..59c8fb8 --- /dev/null +++ b/deploy/base/cert.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: election-tls + namespace: vhsmp +spec: + secretName: election-tls + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - taskarr.milasholsting.dk + diff --git a/deploy/base/deployment.yaml b/deploy/base/deployment.yaml new file mode 100644 index 0000000..3c19b08 --- /dev/null +++ b/deploy/base/deployment.yaml @@ -0,0 +1,77 @@ +# https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: election + namespace: vhsmp + labels: + app: election +spec: + selector: + matchLabels: + app: election + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: election + labels: + app: election + spec: + containers: + - name: election + image: election + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 100m + memory: 100Mi + limits: + cpu: 100m + memory: 100Mi + livenessProbe: + tcpSocket: + port: 3000 + initialDelaySeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + periodSeconds: 10 + ports: + - containerPort: 3000 + name: election + env: + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: election + key: DATABASE_URL + - name: ORIGIN + valueFrom: + secretKeyRef: + name: election + key: ORIGIN + - name: BETTER_AUTH_SECRET + valueFrom: + secretKeyRef: + name: election + key: BETTER_AUTH_SECRET + - name: GITHUB_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: election + key: GITHUB_CLIENT_SECRET + - name: GITHUB_CLIENT_ID + valueFrom: + secretKeyRef: + name: election + key: GITHUB_CLIENT_ID + + restartPolicy: Always +--- + diff --git a/deploy/base/ingress.yaml b/deploy/base/ingress.yaml new file mode 100644 index 0000000..5949de6 --- /dev/null +++ b/deploy/base/ingress.yaml @@ -0,0 +1,19 @@ +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: election-ingress + namespace: vhsmp +spec: + entryPoints: + - websecure + - web + routes: + - match: Host(`election.milasholsting.dk`) + kind: Rule + services: + - name: election + port: 3000 + tls: + secretName: election-tls + + diff --git a/deploy/base/kustomization.yaml b/deploy/base/kustomization.yaml new file mode 100644 index 0000000..58205e4 --- /dev/null +++ b/deploy/base/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: vhsmp + +resources: + - ./deployment.yaml + - ./ingress.yaml + - ./cert.yaml + - ./service.yaml + - ./migration-job.yaml + - ./postgres-service.yaml + - ./postgres-storage.yaml + - ./postgres.yaml diff --git a/deploy/base/migration-job.yaml b/deploy/base/migration-job.yaml new file mode 100644 index 0000000..44f8eb0 --- /dev/null +++ b/deploy/base/migration-job.yaml @@ -0,0 +1,35 @@ +# https://kubernetes.io/docs/concepts/workloads/controllers/job/ +apiVersion: batch/v1 +kind: Job +metadata: + name: election-migration + annotations: + # 1. Tells Argo this is a hook to run during sync + argocd.argoproj.io/hook: Sync + + # 2. Ensures the migration runs BEFORE the deployment + argocd.argoproj.io/sync-wave: "1" + + # 3. Deletes the job after it succeeds so it can run again next time + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation + labels: + app: election-migration +spec: + template: + metadata: + name: election-migration + labels: + app: election-migration + spec: + containers: + - name: election-migration + image: election-migration + env: + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: election + key: DATABASE_URL + + restartPolicy: OnFailure + dnsPolicy: ClusterFirst diff --git a/deploy/base/postgres-service.yaml b/deploy/base/postgres-service.yaml new file mode 100644 index 0000000..e93bcf3 --- /dev/null +++ b/deploy/base/postgres-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: postgres-service +spec: + selector: + app: postgres + ports: + - protocol: TCP + port: 5432 + targetPort: 5432 + type: ClusterIP diff --git a/deploy/base/postgres-storage.yaml b/deploy/base/postgres-storage.yaml new file mode 100644 index 0000000..2a2b129 --- /dev/null +++ b/deploy/base/postgres-storage.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres-pvc +spec: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/deploy/base/postgres.yaml b/deploy/base/postgres.yaml new file mode 100644 index 0000000..6427a06 --- /dev/null +++ b/deploy/base/postgres.yaml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + spec: + containers: + - name: postgres + image: postgres:18 + ports: + - containerPort: 5432 + env: + - name: POSTGRES_DB + value: mydatabase + - name: POSTGRES_USER + value: user123 + - name: POSTGRES_PASSWORD + value: password123 # In production, use a Secret! + volumeMounts: + - mountPath: /var/lib/postgresql + name: postgredb + volumes: + - name: postgredb + persistentVolumeClaim: + claimName: postgres-pvc diff --git a/deploy/base/service.yaml b/deploy/base/service.yaml new file mode 100644 index 0000000..3700791 --- /dev/null +++ b/deploy/base/service.yaml @@ -0,0 +1,16 @@ +# https://kubernetes.io/docs/concepts/services-networking/service/ +apiVersion: v1 +kind: Service +metadata: + name: election + namespace: vhsmp +spec: + selector: + app: election + type: ClusterIP + ports: + - name: election + protocol: TCP + port: 3000 + targetPort: 3000 + diff --git a/deploy/overlays/preview/deployment.yaml b/deploy/overlays/preview/deployment.yaml new file mode 100644 index 0000000..6f4721c --- /dev/null +++ b/deploy/overlays/preview/deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: election # Must match the name in base/ +spec: + replicas: 2 # Scale up for production + template: + spec: + containers: + - name: election # This name must match base EXACTLY + ports: # Adding this back into the patch solves the diff + - containerPort: 3000 + name: election + # Production-specific resource limits + resources: + limits: + cpu: "1" + memory: "1Gi" + requests: + cpu: "500m" + memory: "512Mi" + # Adding a production-only environment variable + env: + - name: NODE_ENV + value: "production" + diff --git a/deploy/overlays/preview/kustomization.yaml b/deploy/overlays/preview/kustomization.yaml new file mode 100644 index 0000000..a095317 --- /dev/null +++ b/deploy/overlays/preview/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# 1. Point to the base manifests +resources: +- ../../base + +# 2. Apply the production-specific changes +patches: +- path: deployment.yaml + target: + kind: Deployment + name: election + +# 4. Change the namespace for this overlay +namespace: vhsmp + +#images: +#- name: election +# newName: reg.milasholsting.dk/vhsmp/election +# newTag: sha-15f1270 diff --git a/deploy/overlays/production/deployment.yaml b/deploy/overlays/production/deployment.yaml new file mode 100644 index 0000000..6f4721c --- /dev/null +++ b/deploy/overlays/production/deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: election # Must match the name in base/ +spec: + replicas: 2 # Scale up for production + template: + spec: + containers: + - name: election # This name must match base EXACTLY + ports: # Adding this back into the patch solves the diff + - containerPort: 3000 + name: election + # Production-specific resource limits + resources: + limits: + cpu: "1" + memory: "1Gi" + requests: + cpu: "500m" + memory: "512Mi" + # Adding a production-only environment variable + env: + - name: NODE_ENV + value: "production" + diff --git a/deploy/overlays/production/kustomization.yaml b/deploy/overlays/production/kustomization.yaml new file mode 100644 index 0000000..c35bc91 --- /dev/null +++ b/deploy/overlays/production/kustomization.yaml @@ -0,0 +1,24 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# 1. Point to the base manifests +resources: +- ../../base + +# 2. Apply the production-specific changes +patches: +- path: deployment.yaml + target: + kind: Deployment + name: election + +# 4. Change the namespace for this overlay +namespace: vhsmp + +images: +- name: election + newName: reg.milasholsting.dk/vhsmp/election + newTag: sha-6017ea9 +- name: election-migration + newName: reg.milasholsting.dk/vhsmp/election-migrator + newTag: sha-6017ea9