diff --git a/apps/guacamole/guacamole.yaml b/apps/guacamole/guacamole.yaml index 3771b78..a70a36d 100644 --- a/apps/guacamole/guacamole.yaml +++ b/apps/guacamole/guacamole.yaml @@ -1,326 +1,344 @@ -# Apache Guacamole - Remote Desktop Gateway -# MySQL 8 + guacd + guacamole web -# ArgoCD managed - BlueJay Lab ---- -apiVersion: v1 -kind: Namespace -metadata: - name: guacamole - labels: - app.kubernetes.io/part-of: bluejay-infra ---- -apiVersion: v1 -kind: Secret -metadata: - name: guac-db-secret - namespace: guacamole -type: Opaque -stringData: - MYSQL_ROOT_PASSWORD: BlueJay-Guac-DB-2026 - MYSQL_DATABASE: guacamole_db - MYSQL_USER: guacamole - MYSQL_PASSWORD: BlueJay-Guac-DB-2026 ---- -# MySQL 8 StatefulSet -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: guac-mysql - namespace: guacamole - labels: - app: guac-mysql -spec: - serviceName: guac-mysql - replicas: 1 - selector: - matchLabels: - app: guac-mysql - template: - metadata: - labels: - app: guac-mysql - spec: - containers: - - name: mysql - image: mysql:8.0 - ports: - - containerPort: 3306 - name: mysql - envFrom: - - secretRef: - name: guac-db-secret - volumeMounts: - - name: guac-mysql-data - mountPath: /var/lib/mysql - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 1Gi - cpu: 500m - livenessProbe: - exec: - command: - - mysqladmin - - ping - - -h - - localhost - initialDelaySeconds: 60 - periodSeconds: 10 - readinessProbe: - exec: - command: - - mysqladmin - - ping - - -h - - localhost - initialDelaySeconds: 30 - periodSeconds: 5 - volumeClaimTemplates: - - metadata: - name: guac-mysql-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: guac-mysql - namespace: guacamole -spec: - selector: - app: guac-mysql - ports: - - port: 3306 - targetPort: 3306 - name: mysql - clusterIP: None ---- -# DB schema init Job -# Generates the MySQL schema and pipes it into the database -apiVersion: batch/v1 -kind: Job -metadata: - name: guacamole-initdb - namespace: guacamole - annotations: - argocd.argoproj.io/hook: PostSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation -spec: - ttlSecondsAfterFinished: 300 - template: - spec: - restartPolicy: OnFailure - initContainers: - - name: wait-for-mysql - image: mysql:8.0 - command: - - sh - - -c - - | - until mysqladmin ping -h guac-mysql --silent; do - echo "Waiting for MySQL..." - sleep 5 - done - containers: - - name: initdb - image: guacamole/guacamole:latest - command: - - sh - - -c - - | - # Generate schema SQL - /opt/guacamole/bin/initdb.sh --mysql > /tmp/initdb.sql - # Apply schema (ignore errors if tables already exist) - mysql -h guac-mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /tmp/initdb.sql || true - env: - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: guac-db-secret - key: MYSQL_ROOT_PASSWORD - - name: MYSQL_DATABASE - valueFrom: - secretKeyRef: - name: guac-db-secret - key: MYSQL_DATABASE ---- -# guacd (Guacamole daemon) -apiVersion: apps/v1 -kind: Deployment -metadata: - name: guacd - namespace: guacamole - labels: - app: guacd -spec: - replicas: 1 - selector: - matchLabels: - app: guacd - template: - metadata: - labels: - app: guacd - spec: - containers: - - name: guacd - image: guacamole/guacd:latest - ports: - - containerPort: 4822 - name: guacd - resources: - requests: - memory: 128Mi - cpu: 100m - limits: - memory: 512Mi - cpu: 500m - livenessProbe: - tcpSocket: - port: 4822 - initialDelaySeconds: 15 - periodSeconds: 10 ---- -apiVersion: v1 -kind: Service -metadata: - name: guacd - namespace: guacamole -spec: - selector: - app: guacd - ports: - - port: 4822 - targetPort: 4822 - name: guacd ---- -# Guacamole Web Application -apiVersion: apps/v1 -kind: Deployment -metadata: - name: guacamole - namespace: guacamole - labels: - app: guacamole -spec: - replicas: 1 - selector: - matchLabels: - app: guacamole - template: - metadata: - labels: - app: guacamole - spec: - containers: - - name: guacamole - image: guacamole/guacamole:latest - ports: - - containerPort: 8080 - name: http - env: - - name: GUACD_HOSTNAME - value: guacd - - name: GUACD_PORT - value: "4822" - - name: MYSQL_HOSTNAME - value: guac-mysql - - name: MYSQL_PORT - value: "3306" - - name: MYSQL_DATABASE - valueFrom: - secretKeyRef: - name: guac-db-secret - key: MYSQL_DATABASE - - name: MYSQL_USER - valueFrom: - secretKeyRef: - name: guac-db-secret - key: MYSQL_USER - - name: MYSQL_PASSWORD - valueFrom: - secretKeyRef: - name: guac-db-secret - key: MYSQL_PASSWORD - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 1Gi - cpu: 500m - livenessProbe: - httpGet: - path: /guacamole/ - port: 8080 - initialDelaySeconds: 120 - periodSeconds: 10 - readinessProbe: - httpGet: - path: /guacamole/ - port: 8080 - initialDelaySeconds: 60 - periodSeconds: 5 ---- -apiVersion: v1 -kind: Service -metadata: - name: guacamole - namespace: guacamole -spec: - selector: - app: guacamole - ports: - - port: 8080 - targetPort: 8080 - name: http ---- -# Traefik addPrefix middleware -# External URL guac.iamworkin.lan/ gets prefix /guacamole added -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: guac-add-prefix - namespace: guacamole -spec: - addPrefix: - prefix: /guacamole ---- -# TLS Certificate via cert-manager -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: guacamole-tls - namespace: guacamole -spec: - secretName: guacamole-tls - issuerRef: - name: step-ca-acme - kind: ClusterIssuer - dnsNames: - - guac.iamworkin.lan ---- -# Traefik IngressRoute -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: guacamole - namespace: guacamole -spec: - entryPoints: - - websecure - routes: - - match: Host(`guac.iamworkin.lan`) - kind: Rule - middlewares: - - name: guac-add-prefix - services: - - name: guacamole - port: 8080 - tls: - secretName: guacamole-tls +# Apache Guacamole - Remote Desktop Gateway +# MySQL 8 + guacd + guacamole web +# ArgoCD managed - BlueJay Lab +# DB credentials sourced from 1Password via OnePasswordItem CRD (guacamole-credentials) +# Note: guacamole-credentials contains Guacamole admin UI creds (username/password), +# not MySQL DB creds. MySQL root/user password is kept in guac-db-secret (still inline) +# because 1Password item lacks DB-specific fields. See gap notes below. +--- +apiVersion: v1 +kind: Namespace +metadata: + name: guacamole + labels: + app.kubernetes.io/part-of: bluejay-infra +--- +apiVersion: v1 +kind: Secret +metadata: + name: guac-db-secret + namespace: guacamole +type: Opaque +stringData: + MYSQL_ROOT_PASSWORD: BlueJay-Guac-DB-2026 + MYSQL_DATABASE: guacamole_db + MYSQL_USER: guacamole + MYSQL_PASSWORD: BlueJay-Guac-DB-2026 +--- +# MySQL 8 StatefulSet +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: guac-mysql + namespace: guacamole + labels: + app: guac-mysql +spec: + serviceName: guac-mysql + replicas: 1 + selector: + matchLabels: + app: guac-mysql + template: + metadata: + labels: + app: guac-mysql + spec: + containers: + - name: mysql + image: mysql:8.0 + ports: + - containerPort: 3306 + name: mysql + envFrom: + - secretRef: + name: guac-db-secret + volumeMounts: + - name: guac-mysql-data + mountPath: /var/lib/mysql + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 1Gi + cpu: 500m + livenessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + initialDelaySeconds: 60 + periodSeconds: 10 + readinessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + initialDelaySeconds: 30 + periodSeconds: 5 + volumeClaimTemplates: + - metadata: + name: guac-mysql-data + spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: guac-mysql + namespace: guacamole +spec: + selector: + app: guac-mysql + ports: + - port: 3306 + targetPort: 3306 + name: mysql + clusterIP: None +--- +# DB schema init Job +# Generates the MySQL schema and pipes it into the database +apiVersion: batch/v1 +kind: Job +metadata: + name: guacamole-initdb + namespace: guacamole + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + ttlSecondsAfterFinished: 300 + template: + spec: + restartPolicy: OnFailure + initContainers: + - name: wait-for-mysql + image: mysql:8.0 + command: + - sh + - -c + - | + until mysqladmin ping -h guac-mysql --silent; do + echo "Waiting for MySQL..." + sleep 5 + done + containers: + - name: initdb + image: guacamole/guacamole:latest + command: + - sh + - -c + - | + # Generate schema SQL + /opt/guacamole/bin/initdb.sh --mysql > /tmp/initdb.sql + # Apply schema (ignore errors if tables already exist) + mysql -h guac-mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /tmp/initdb.sql || true + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: guac-db-secret + key: MYSQL_ROOT_PASSWORD + - name: MYSQL_DATABASE + valueFrom: + secretKeyRef: + name: guac-db-secret + key: MYSQL_DATABASE +--- +# guacd (Guacamole daemon) +apiVersion: apps/v1 +kind: Deployment +metadata: + name: guacd + namespace: guacamole + labels: + app: guacd +spec: + replicas: 1 + selector: + matchLabels: + app: guacd + template: + metadata: + labels: + app: guacd + spec: + containers: + - name: guacd + image: guacamole/guacd:latest + ports: + - containerPort: 4822 + name: guacd + resources: + requests: + memory: 128Mi + cpu: 100m + limits: + memory: 512Mi + cpu: 500m + livenessProbe: + tcpSocket: + port: 4822 + initialDelaySeconds: 15 + periodSeconds: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: guacd + namespace: guacamole +spec: + selector: + app: guacd + ports: + - port: 4822 + targetPort: 4822 + name: guacd +--- +# Guacamole Web Application +apiVersion: apps/v1 +kind: Deployment +metadata: + name: guacamole + namespace: guacamole + labels: + app: guacamole +spec: + replicas: 1 + selector: + matchLabels: + app: guacamole + template: + metadata: + labels: + app: guacamole + spec: + containers: + - name: guacamole + image: guacamole/guacamole:latest + ports: + - containerPort: 8080 + name: http + env: + - name: GUACD_HOSTNAME + value: guacd + - name: GUACD_PORT + value: "4822" + - name: MYSQL_HOSTNAME + value: guac-mysql + - name: MYSQL_PORT + value: "3306" + - name: MYSQL_DATABASE + valueFrom: + secretKeyRef: + name: guac-db-secret + key: MYSQL_DATABASE + - name: MYSQL_USER + valueFrom: + secretKeyRef: + name: guac-db-secret + key: MYSQL_USER + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: guac-db-secret + key: MYSQL_PASSWORD + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 1Gi + cpu: 500m + livenessProbe: + httpGet: + path: /guacamole/ + port: 8080 + initialDelaySeconds: 120 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /guacamole/ + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: guacamole + namespace: guacamole +spec: + selector: + app: guacamole + ports: + - port: 8080 + targetPort: 8080 + name: http +--- +# Traefik addPrefix middleware +# External URL guac.iamworkin.lan/ gets prefix /guacamole added +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: guac-add-prefix + namespace: guacamole +spec: + addPrefix: + prefix: /guacamole +--- +# TLS Certificate via cert-manager +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: guacamole-tls + namespace: guacamole +spec: + secretName: guacamole-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - guac.iamworkin.lan +--- +# Traefik IngressRoute +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: guacamole + namespace: guacamole +spec: + entryPoints: + - websecure + routes: + - match: Host(`guac.iamworkin.lan`) + kind: Rule + middlewares: + - name: guac-add-prefix + services: + - name: guacamole + port: 8080 + tls: + secretName: guacamole-tls +--- +# 1Password secret sync — creates guacamole-credentials K8s Secret +# Fields: username, password, URL, Note +# NOTE: This secret contains Guacamole admin UI credentials only. +# MySQL DB credentials (MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD) are NOT in 1Password yet. +# To fully externalize: add DB-User, DB-Password, DB-Root-Password fields to the +# "Guacamole" 1Password item, then replace guac-db-secret refs with guacamole-credentials. +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: guacamole-credentials + namespace: guacamole +spec: + itemPath: vaults/IAmWorkin/items/Guacamole diff --git a/apps/matrix/matrix.yaml b/apps/matrix/matrix.yaml index ac35d05..b062a70 100644 --- a/apps/matrix/matrix.yaml +++ b/apps/matrix/matrix.yaml @@ -1,6 +1,8 @@ # Matrix Synapse + Element Web # PostgreSQL 16 + Synapse homeserver + Element Web client # ArgoCD managed - BlueJay Lab +# DB credentials sourced from 1Password via OnePasswordItem CRD (matrix-credentials) +# Synapse homeserver.yaml DB password injected at runtime via init container --- apiVersion: v1 kind: Namespace @@ -9,26 +11,15 @@ metadata: labels: app.kubernetes.io/part-of: bluejay-infra --- -apiVersion: v1 -kind: Secret -metadata: - name: matrix-db-secret - namespace: matrix -type: Opaque -stringData: - POSTGRES_USER: synapse - POSTGRES_PASSWORD: BlueJay-Matrix-DB-2026 - POSTGRES_DB: synapse - POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" ---- -# Synapse homeserver.yaml ConfigMap +# Synapse homeserver.yaml template ConfigMap +# DB password placeholder __DB_PASSWORD__ is replaced at pod startup by init container apiVersion: v1 kind: ConfigMap metadata: name: synapse-config namespace: matrix data: - homeserver.yaml: | + homeserver.yaml.template: | server_name: "iamworkin.lan" pid_file: /data/homeserver.pid public_baseurl: "https://matrix.iamworkin.lan/" @@ -44,8 +35,8 @@ data: database: name: psycopg2 args: - user: synapse - password: BlueJay-Matrix-DB-2026 + user: __DB_USER__ + password: __DB_PASSWORD__ database: synapse host: matrix-postgres port: 5432 @@ -80,6 +71,7 @@ data: disable_existing_loggers: false --- # PostgreSQL 16 StatefulSet +# Credentials from 1Password-synced matrix-credentials secret apiVersion: apps/v1 kind: StatefulSet metadata: @@ -104,9 +96,21 @@ spec: ports: - containerPort: 5432 name: postgres - envFrom: - - secretRef: - name: matrix-db-secret + env: + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: matrix-credentials + key: DB-User + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: matrix-credentials + key: DB-Password + - name: POSTGRES_DB + value: synapse + - name: POSTGRES_INITDB_ARGS + value: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" volumeMounts: - name: matrix-postgres-data mountPath: /var/lib/postgresql/data @@ -163,7 +167,8 @@ spec: requests: storage: 2Gi --- -# Synapse init job: generate signing key if missing +# Synapse Deployment +# Init container injects DB credentials from 1Password secret into homeserver.yaml apiVersion: apps/v1 kind: Deployment metadata: @@ -192,7 +197,13 @@ spec: args: - | if [ \! -f /data/signing.key ]; then - python -m synapse.app.homeserver --generate-keys --config-path /config/homeserver.yaml + python -m synapse.app.homeserver --generate-keys --config-path /config-template/homeserver.yaml.template 2>/dev/null || true + # If key generation fails with template, create a minimal config for key gen + if [ \! -f /data/signing.key ]; then + echo server_name: iamworkin.lan > /tmp/minimal.yaml + echo signing_key_path: /data/signing.key >> /tmp/minimal.yaml + python -c "from signedjson.key import generate_signing_key, write_signing_keys; import sys; key = generate_signing_key(a_auto); write_signing_keys(open(/data/signing.key,w), [key])" 2>/dev/null || true + fi fi chown 991:991 /data/signing.key 2>/dev/null || true chmod 644 /data/signing.key 2>/dev/null || true @@ -201,7 +212,34 @@ spec: volumeMounts: - name: synapse-data mountPath: /data - - name: synapse-config + - name: synapse-config-template + mountPath: /config-template + - name: inject-credentials + image: busybox:latest + command: ["sh", "-c"] + args: + - | + # Copy template and substitute DB credentials from 1Password secret + cp /config-template/log.config /config/log.config + sed -e "s/__DB_PASSWORD__/${DB_PASSWORD}/g" \ + -e "s/__DB_USER__/${DB_USER}/g" \ + /config-template/homeserver.yaml.template > /config/homeserver.yaml + echo "Credentials injected into homeserver.yaml" + env: + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: matrix-credentials + key: DB-Password + - name: DB_USER + valueFrom: + secretKeyRef: + name: matrix-credentials + key: DB-User + volumeMounts: + - name: synapse-config-template + mountPath: /config-template + - name: synapse-config-rendered mountPath: /config containers: - name: synapse @@ -217,7 +255,7 @@ spec: volumeMounts: - name: synapse-data mountPath: /data - - name: synapse-config + - name: synapse-config-rendered mountPath: /config resources: requests: @@ -242,9 +280,11 @@ spec: - name: synapse-data persistentVolumeClaim: claimName: synapse-data - - name: synapse-config + - name: synapse-config-template configMap: name: synapse-config + - name: synapse-config-rendered + emptyDir: {} --- apiVersion: v1 kind: Service @@ -407,3 +447,13 @@ spec: port: 80 tls: secretName: element-tls +--- +# 1Password secret sync — creates matrix-credentials K8s Secret +# Fields: DB-User, DB-Password, Registration-Secret, username, password, URL +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: matrix-credentials + namespace: matrix +spec: + itemPath: vaults/IAmWorkin/items/Matrix Synapse diff --git a/apps/zabbix/zabbix.yaml b/apps/zabbix/zabbix.yaml index f394b09..dea930d 100644 --- a/apps/zabbix/zabbix.yaml +++ b/apps/zabbix/zabbix.yaml @@ -1,320 +1,315 @@ -# Zabbix 7.2 Monitoring Stack -# PostgreSQL 16 + Zabbix Server + Zabbix Web (nginx) -# ArgoCD managed - BlueJay Lab ---- -apiVersion: v1 -kind: Namespace -metadata: - name: zabbix - labels: - app.kubernetes.io/part-of: bluejay-infra ---- -apiVersion: v1 -kind: Secret -metadata: - name: zabbix-db-secret - namespace: zabbix -type: Opaque -stringData: - POSTGRES_USER: zabbix - POSTGRES_PASSWORD: BlueJay-ZabbixDB-2026 - POSTGRES_DB: zabbix ---- -apiVersion: v1 -kind: Secret -metadata: - name: zabbix-admin-secret - namespace: zabbix -type: Opaque -stringData: - ZBX_ADMIN_PASSWORD: BlueJay-NOC-2026 ---- -# PostgreSQL 16 StatefulSet -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: zabbix-postgres - namespace: zabbix - labels: - app: zabbix-postgres -spec: - serviceName: zabbix-postgres - replicas: 1 - selector: - matchLabels: - app: zabbix-postgres - template: - metadata: - labels: - app: zabbix-postgres - spec: - containers: - - name: postgres - image: postgres:16-alpine - ports: - - containerPort: 5432 - name: postgres - envFrom: - - secretRef: - name: zabbix-db-secret - volumeMounts: - - name: zabbix-postgres-data - mountPath: /var/lib/postgresql/data - subPath: pgdata - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 512Mi - cpu: 500m - livenessProbe: - exec: - command: - - pg_isready - - -U - - zabbix - initialDelaySeconds: 30 - periodSeconds: 10 - readinessProbe: - exec: - command: - - pg_isready - - -U - - zabbix - initialDelaySeconds: 5 - periodSeconds: 5 - volumeClaimTemplates: - - metadata: - name: zabbix-postgres-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 10Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: zabbix-postgres - namespace: zabbix -spec: - selector: - app: zabbix-postgres - ports: - - port: 5432 - targetPort: 5432 - name: postgres - clusterIP: None ---- -# Zabbix Server -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zabbix-server - namespace: zabbix - labels: - app: zabbix-server -spec: - replicas: 1 - selector: - matchLabels: - app: zabbix-server - template: - metadata: - labels: - app: zabbix-server - spec: - containers: - - name: zabbix-server - image: zabbix/zabbix-server-pgsql:7.2-alpine-latest - ports: - - containerPort: 10051 - name: trapper - env: - - name: DB_SERVER_HOST - value: zabbix-postgres - - name: DB_SERVER_PORT - value: "5432" - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: zabbix-db-secret - key: POSTGRES_USER - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: zabbix-db-secret - key: POSTGRES_PASSWORD - - name: POSTGRES_DB - valueFrom: - secretKeyRef: - name: zabbix-db-secret - key: POSTGRES_DB - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 1Gi - cpu: "1" - livenessProbe: - tcpSocket: - port: 10051 - initialDelaySeconds: 60 - periodSeconds: 10 - readinessProbe: - tcpSocket: - port: 10051 - initialDelaySeconds: 30 - periodSeconds: 5 ---- -apiVersion: v1 -kind: Service -metadata: - name: zabbix-server - namespace: zabbix -spec: - selector: - app: zabbix-server - ports: - - port: 10051 - targetPort: 10051 - name: trapper ---- -apiVersion: v1 -kind: Service -metadata: - name: zabbix-trapper - namespace: zabbix - annotations: - metallb.universe.tf/loadBalancerIPs: 10.0.56.203 -spec: - type: LoadBalancer - selector: - app: zabbix-server - ports: - - port: 10051 - targetPort: 10051 - name: trapper - protocol: TCP ---- -# Zabbix Web (nginx + PostgreSQL) -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zabbix-web - namespace: zabbix - labels: - app: zabbix-web -spec: - replicas: 1 - selector: - matchLabels: - app: zabbix-web - template: - metadata: - labels: - app: zabbix-web - spec: - containers: - - name: zabbix-web - image: zabbix/zabbix-web-nginx-pgsql:7.2-alpine-latest - ports: - - containerPort: 8080 - name: http - env: - - name: ZBX_SERVER_HOST - value: zabbix-server - - name: ZBX_SERVER_NAME - value: "BlueJay NOC" - - name: PHP_TZ - value: America/Chicago - - name: DB_SERVER_HOST - value: zabbix-postgres - - name: DB_SERVER_PORT - value: "5432" - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: zabbix-db-secret - key: POSTGRES_USER - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: zabbix-db-secret - key: POSTGRES_PASSWORD - - name: POSTGRES_DB - valueFrom: - secretKeyRef: - name: zabbix-db-secret - key: POSTGRES_DB - - name: ZBX_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - name: zabbix-admin-secret - key: ZBX_ADMIN_PASSWORD - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 512Mi - cpu: 500m - livenessProbe: - httpGet: - path: / - port: 8080 - initialDelaySeconds: 60 - periodSeconds: 10 - readinessProbe: - httpGet: - path: / - port: 8080 - initialDelaySeconds: 30 - periodSeconds: 5 ---- -apiVersion: v1 -kind: Service -metadata: - name: zabbix-web - namespace: zabbix -spec: - selector: - app: zabbix-web - ports: - - port: 8080 - targetPort: 8080 - name: http ---- -# TLS Certificate via cert-manager -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: zabbix-tls - namespace: zabbix -spec: - secretName: zabbix-tls - issuerRef: - name: step-ca-acme - kind: ClusterIssuer - dnsNames: - - zabbix.iamworkin.lan ---- -# Traefik IngressRoute -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: zabbix-web - namespace: zabbix -spec: - entryPoints: - - websecure - routes: - - match: Host(`zabbix.iamworkin.lan`) - kind: Rule - services: - - name: zabbix-web - port: 8080 - tls: - secretName: zabbix-tls +# Zabbix 7.2 Monitoring Stack +# PostgreSQL 16 + Zabbix Server + Zabbix Web (nginx) +# ArgoCD managed - BlueJay Lab +# Credentials sourced from 1Password via OnePasswordItem CRD (zabbix-credentials) +--- +apiVersion: v1 +kind: Namespace +metadata: + name: zabbix + labels: + app.kubernetes.io/part-of: bluejay-infra +--- +# PostgreSQL 16 StatefulSet +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: zabbix-postgres + namespace: zabbix + labels: + app: zabbix-postgres +spec: + serviceName: zabbix-postgres + replicas: 1 + selector: + matchLabels: + app: zabbix-postgres + template: + metadata: + labels: + app: zabbix-postgres + spec: + containers: + - name: postgres + image: postgres:16-alpine + ports: + - containerPort: 5432 + name: postgres + env: + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: DB-User + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: DB-Password + - name: POSTGRES_DB + value: zabbix + volumeMounts: + - name: zabbix-postgres-data + mountPath: /var/lib/postgresql/data + subPath: pgdata + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 512Mi + cpu: 500m + livenessProbe: + exec: + command: + - pg_isready + - -U + - zabbix + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - pg_isready + - -U + - zabbix + initialDelaySeconds: 5 + periodSeconds: 5 + volumeClaimTemplates: + - metadata: + name: zabbix-postgres-data + spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: zabbix-postgres + namespace: zabbix +spec: + selector: + app: zabbix-postgres + ports: + - port: 5432 + targetPort: 5432 + name: postgres + clusterIP: None +--- +# Zabbix Server +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zabbix-server + namespace: zabbix + labels: + app: zabbix-server +spec: + replicas: 1 + selector: + matchLabels: + app: zabbix-server + template: + metadata: + labels: + app: zabbix-server + spec: + containers: + - name: zabbix-server + image: zabbix/zabbix-server-pgsql:7.2-alpine-latest + ports: + - containerPort: 10051 + name: trapper + env: + - name: DB_SERVER_HOST + value: zabbix-postgres + - name: DB_SERVER_PORT + value: "5432" + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: DB-User + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: DB-Password + - name: POSTGRES_DB + value: zabbix + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 1Gi + cpu: "1" + livenessProbe: + tcpSocket: + port: 10051 + initialDelaySeconds: 60 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: 10051 + initialDelaySeconds: 30 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: zabbix-server + namespace: zabbix +spec: + selector: + app: zabbix-server + ports: + - port: 10051 + targetPort: 10051 + name: trapper +--- +apiVersion: v1 +kind: Service +metadata: + name: zabbix-trapper + namespace: zabbix + annotations: + metallb.universe.tf/loadBalancerIPs: 10.0.56.203 +spec: + type: LoadBalancer + selector: + app: zabbix-server + ports: + - port: 10051 + targetPort: 10051 + name: trapper + protocol: TCP +--- +# Zabbix Web (nginx + PostgreSQL) +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zabbix-web + namespace: zabbix + labels: + app: zabbix-web +spec: + replicas: 1 + selector: + matchLabels: + app: zabbix-web + template: + metadata: + labels: + app: zabbix-web + spec: + containers: + - name: zabbix-web + image: zabbix/zabbix-web-nginx-pgsql:7.2-alpine-latest + ports: + - containerPort: 8080 + name: http + env: + - name: ZBX_SERVER_HOST + value: zabbix-server + - name: ZBX_SERVER_NAME + value: "BlueJay NOC" + - name: PHP_TZ + value: America/Chicago + - name: DB_SERVER_HOST + value: zabbix-postgres + - name: DB_SERVER_PORT + value: "5432" + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: DB-User + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: DB-Password + - name: POSTGRES_DB + value: zabbix + - name: ZBX_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: zabbix-credentials + key: password + resources: + requests: + memory: 128Mi + cpu: 50m + limits: + memory: 512Mi + cpu: 500m + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: zabbix-web + namespace: zabbix +spec: + selector: + app: zabbix-web + ports: + - port: 8080 + targetPort: 8080 + name: http +--- +# TLS Certificate via cert-manager +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: zabbix-tls + namespace: zabbix +spec: + secretName: zabbix-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - zabbix.iamworkin.lan +--- +# Traefik IngressRoute +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: zabbix-web + namespace: zabbix +spec: + entryPoints: + - websecure + routes: + - match: Host(`zabbix.iamworkin.lan`) + kind: Rule + services: + - name: zabbix-web + port: 8080 + tls: + secretName: zabbix-tls +--- +# 1Password secret sync — creates zabbix-credentials K8s Secret +# Fields: DB-User, DB-Password, username, password, URL +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: zabbix-credentials + namespace: zabbix +spec: + itemPath: vaults/IAmWorkin/items/Zabbix Admin