Merge pull request #120 from sirius0xdev/feat/trading-platform-manifests
feat: add trading-platform K8s manifests for customer1
This commit is contained in:
commit
67e45a4464
60 changed files with 3747 additions and 1 deletions
130
.github/workflows/osint-dashboard-infra.yml
vendored
Normal file
130
.github/workflows/osint-dashboard-infra.yml
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
name: OSINT Dashboard Infrastructure
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths:
|
||||
- 'apps/base/osint-dashboard/**'
|
||||
- 'apps/staging/osint-dashboard/**'
|
||||
- 'clusters/devops-lab/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'apps/base/osint-dashboard/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: gcr.io/devops-lab-cluster
|
||||
CHART_PATH: apps/base/osint-dashboard
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint Helm Chart
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v3
|
||||
with:
|
||||
version: v3.14.0
|
||||
|
||||
- name: Set up chart-testing
|
||||
uses: helm/chart-testing-action@v2
|
||||
|
||||
- name: Run helm lint
|
||||
run: |
|
||||
helm lint ${{ env.CHART_PATH }}
|
||||
helm lint ${{ env.CHART_PATH }} -f ${{ env.CHART_PATH }}/values.yaml
|
||||
|
||||
- name: Run chart-testing lint
|
||||
run: |
|
||||
ct lint --target-branch ${{ github.event.pull_request.base.ref || github.ref_name }} --chart-dirs apps/base --validate-maintainers=false
|
||||
|
||||
template:
|
||||
name: Render Templates
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v3
|
||||
with:
|
||||
version: v3.14.0
|
||||
|
||||
- name: Render templates (dev)
|
||||
run: |
|
||||
helm template osint-dashboard ${{ env.CHART_PATH }} --namespace customer1 --values ${{ env.CHART_PATH }}/values.yaml --output-template-files > /dev/null
|
||||
|
||||
- name: Render templates (prod override)
|
||||
run: |
|
||||
helm template osint-dashboard ${{ env.CHART_PATH }} --namespace customer1 --values ${{ env.CHART_PATH }}/values.yaml --set postgresql.instances=3 --set nats.replicaCount=3 --set redis.replica.replicaCount=2 --set minio.replicaCount=4 --output-template-files > /dev/null
|
||||
|
||||
validate-yaml:
|
||||
name: Validate YAML
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install yamllint
|
||||
run: pip install yamllint
|
||||
|
||||
- name: Lint YAML files
|
||||
run: |
|
||||
yamllint -d relaxed --ignore '*/gotk-components.yaml' ${{ env.CHART_PATH }}/Chart.yaml ${{ env.CHART_PATH }}/values.yaml ${{ env.CHART_PATH }}/templates/
|
||||
|
||||
security-scan:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Trivy Helm chart scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: 'config'
|
||||
scan-ref: ${{ env.CHART_PATH }}/templates/
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
|
||||
- name: Upload Trivy results
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
deploy-staging:
|
||||
name: Deploy to Staging
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, validate-yaml]
|
||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||
environment:
|
||||
name: staging
|
||||
url: https://dashboard.siriusdevops.com
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Flux Kustomization already applied
|
||||
run: |
|
||||
echo "Flux CD will automatically pick up changes from master branch."
|
||||
echo "Kustomization: customer1 -> apps/staging/customer1"
|
||||
echo "No manual deploy step needed — GitOps loop handles it."
|
||||
|
||||
- name: Notify deployment
|
||||
if: always()
|
||||
run: |
|
||||
echo "Deployment triggered via Flux CD GitOps loop"
|
||||
echo "Check Flux status: flux get kustomizations -n flux-system"
|
||||
128
apps/base/customer1/hermes-db/kafka-broker.yaml
Normal file
128
apps/base/customer1/hermes-db/kafka-broker.yaml
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# Kafka broker (KRaft mode — no ZooKeeper required)
|
||||
# Single-broker for dev/staging; scale replicas for production
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trading-kafka
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-kafka
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: trading-kafka
|
||||
ports:
|
||||
- name: internal
|
||||
port: 9092
|
||||
targetPort: 9092
|
||||
- name: controller
|
||||
port: 9093
|
||||
targetPort: 9093
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trading-kafka-config
|
||||
namespace: customer1
|
||||
data:
|
||||
server.properties: |
|
||||
process.roles=broker,controller
|
||||
node.id=1
|
||||
controller.quorum.voters=1@trading-kafka-0.trading-kafka.customer1.svc.cluster.local:9093
|
||||
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
|
||||
advertised.listeners=PLAINTEXT://trading-kafka-0.trading-kafka.customer1.svc.cluster.local:9092
|
||||
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
|
||||
controller.listener.names=CONTROLLER
|
||||
inter.broker.listener.name=PLAINTEXT
|
||||
log.dirs=/var/lib/kafka/data
|
||||
num.partitions=3
|
||||
default.replication.factor=1
|
||||
offsets.topic.replication.factor=1
|
||||
transaction.state.log.replication.factor=1
|
||||
transaction.state.log.min.isr=1
|
||||
auto.create.topics.enable=true
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: trading-kafka
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-kafka
|
||||
spec:
|
||||
serviceName: trading-kafka
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trading-kafka
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trading-kafka
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: kafka
|
||||
image: apache/kafka:3.9.0
|
||||
ports:
|
||||
- containerPort: 9092
|
||||
name: internal
|
||||
- containerPort: 9093
|
||||
name: controller
|
||||
env:
|
||||
- name: KAFKA_HEAP_OPTS
|
||||
value: "-Xmx512M -Xms256M"
|
||||
- name: CLUSTER_ID
|
||||
value: "trading-kafka-cluster-01"
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- |
|
||||
export KAFKA_CLUSTER_ID="$(/opt/kafka/bin/kafka-storage.sh random-uuid)"
|
||||
/opt/kafka/bin/kafka-storage.sh format -t $KAFKA_CLUSTER_ID -c /etc/kafka/server.properties --ignore-formatted
|
||||
exec /opt/kafka/bin/kafka-server-start.sh /etc/kafka/server.properties
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/kafka
|
||||
- name: data
|
||||
mountPath: /var/lib/kafka/data
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 9092
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 5
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 9092
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: trading-kafka-config
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
|
|
@ -9,3 +9,5 @@ resources:
|
|||
- trading-data-db.yaml
|
||||
- agent-memory-db.yaml
|
||||
- hermes-scheduled-backup.yaml
|
||||
- kafka-broker.yaml
|
||||
- redis-cluster.yaml
|
||||
|
|
|
|||
103
apps/base/customer1/hermes-db/redis-cluster.yaml
Normal file
103
apps/base/customer1/hermes-db/redis-cluster.yaml
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Redis single-instance for trading platform caching
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trading-redis
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-redis
|
||||
spec:
|
||||
selector:
|
||||
app: trading-redis
|
||||
ports:
|
||||
- port: 6379
|
||||
targetPort: 6379
|
||||
name: redis
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trading-redis-config
|
||||
namespace: customer1
|
||||
data:
|
||||
redis.conf: |
|
||||
maxmemory 256mb
|
||||
maxmemory-policy allkeys-lru
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
appendonly yes
|
||||
appendfsync everysec
|
||||
dir /data
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: trading-redis
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-redis
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trading-redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trading-redis
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999
|
||||
fsGroup: 999
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.4-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
args:
|
||||
- redis-server
|
||||
- /etc/redis/redis.conf
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/redis
|
||||
- name: data
|
||||
mountPath: /data
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: trading-redis-config
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
|
|
@ -7,3 +7,4 @@ resources:
|
|||
- service.yaml
|
||||
- siriusdevops-site
|
||||
- waitlist-api
|
||||
- trading-platform
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trading-dashboard-config
|
||||
namespace: customer1
|
||||
data:
|
||||
DB_HOST: "hermes-pgdb-rw.customer1.svc.cluster.local"
|
||||
DB_PORT: "5432"
|
||||
DB_NAME: "trading_data"
|
||||
DATA_SERVICE_URL: "http://trading-data-service.customer1.svc.cluster.local"
|
||||
EXECUTE_SERVICE_URL: "http://trading-execute-service.customer1.svc.cluster.local"
|
||||
NEWS_SERVICE_URL: "http://trading-news-service.customer1.svc.cluster.local"
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trading-data-service-config
|
||||
namespace: customer1
|
||||
data:
|
||||
DB_HOST: "hermes-pgdb-rw.customer1.svc.cluster.local"
|
||||
DB_PORT: "5432"
|
||||
DB_NAME: "trading_data"
|
||||
REDIS_HOST: "trading-redis.customer1.svc.cluster.local"
|
||||
REDIS_PORT: "6379"
|
||||
KAFKA_BROKER: "trading-kafka.customer1.svc.cluster.local:9092"
|
||||
LOG_LEVEL: "info"
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trading-execute-service-config
|
||||
namespace: customer1
|
||||
data:
|
||||
DB_HOST: "hermes-pgdb-rw.customer1.svc.cluster.local"
|
||||
DB_PORT: "5432"
|
||||
DB_NAME: "trading_data"
|
||||
REDIS_HOST: "trading-redis.customer1.svc.cluster.local"
|
||||
REDIS_PORT: "6379"
|
||||
KAFKA_BROKER: "trading-kafka.customer1.svc.cluster.local:9092"
|
||||
LOG_LEVEL: "info"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- data-service-config.yaml
|
||||
- execute-service-config.yaml
|
||||
- news-service-config.yaml
|
||||
- dashboard-config.yaml
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trading-news-service-config
|
||||
namespace: customer1
|
||||
data:
|
||||
DB_HOST: "hermes-pgdb-rw.customer1.svc.cluster.local"
|
||||
DB_PORT: "5432"
|
||||
DB_NAME: "trading_data"
|
||||
REDIS_HOST: "trading-redis.customer1.svc.cluster.local"
|
||||
REDIS_PORT: "6379"
|
||||
NEWS_FETCH_INTERVAL: "300"
|
||||
LOG_LEVEL: "info"
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: trading-dashboard
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-dashboard
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trading-dashboard
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trading-dashboard
|
||||
annotations:
|
||||
checksum/config: trading-dashboard-config
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: dashboard
|
||||
image: ghcr.io/sirius0xdev/trading-dashboard:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: trading-dashboard-config
|
||||
env:
|
||||
- name: DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: username
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: password
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /api/health
|
||||
port: 8000
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
failureThreshold: 6
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/health
|
||||
port: 8000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/health
|
||||
port: 8000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
18
apps/base/customer1/trading-platform/dashboard/service.yaml
Normal file
18
apps/base/customer1/trading-platform/dashboard/service.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trading-dashboard-svc
|
||||
namespace: customer1
|
||||
annotations:
|
||||
tailscale.com/expose: "true"
|
||||
tailscale.com/hostname: "trading-dashboard"
|
||||
tailscale.com/tags: "tag:k8s-operator"
|
||||
tailscale.com/ports: "http:80"
|
||||
spec:
|
||||
selector:
|
||||
app: trading-dashboard
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8000
|
||||
name: http
|
||||
type: ClusterIP
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: trading-data-service
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-data-service
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trading-data-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trading-data-service
|
||||
annotations:
|
||||
checksum/config: trading-data-service-config
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: data-service
|
||||
image: ghcr.io/sirius0xdev/trading-data-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8001
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: trading-data-service-config
|
||||
env:
|
||||
- name: DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: username
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: password
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8001
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
failureThreshold: 6
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8001
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8001
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trading-data-service
|
||||
namespace: customer1
|
||||
annotations:
|
||||
tailscale.com/expose: "true"
|
||||
tailscale.com/hostname: "trading-data-service"
|
||||
tailscale.com/tags: "tag:k8s-operator"
|
||||
tailscale.com/ports: "http:80"
|
||||
spec:
|
||||
selector:
|
||||
app: trading-data-service
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8001
|
||||
name: http
|
||||
type: ClusterIP
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: trading-execute-service
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-execute-service
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trading-execute-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trading-execute-service
|
||||
annotations:
|
||||
checksum/config: trading-execute-service-config
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: execute-service
|
||||
image: ghcr.io/sirius0xdev/trading-execute-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8002
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: trading-execute-service-config
|
||||
env:
|
||||
- name: DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: username
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: password
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8002
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
failureThreshold: 6
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8002
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8002
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trading-execute-service
|
||||
namespace: customer1
|
||||
annotations:
|
||||
tailscale.com/expose: "true"
|
||||
tailscale.com/hostname: "trading-execute-service"
|
||||
tailscale.com/tags: "tag:k8s-operator"
|
||||
tailscale.com/ports: "http:80"
|
||||
spec:
|
||||
selector:
|
||||
app: trading-execute-service
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8002
|
||||
name: http
|
||||
type: ClusterIP
|
||||
13
apps/base/customer1/trading-platform/kustomization.yaml
Normal file
13
apps/base/customer1/trading-platform/kustomization.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: customer1
|
||||
|
||||
resources:
|
||||
- data-service
|
||||
- execute-service
|
||||
- news-service
|
||||
- dashboard
|
||||
- configmaps
|
||||
- secrets
|
||||
- network-policies
|
||||
- routes
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- trading-network-policies.yaml
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: trading-platform-netpol
|
||||
namespace: customer1
|
||||
spec:
|
||||
podSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- trading-data-service
|
||||
- trading-execute-service
|
||||
- trading-news-service
|
||||
- trading-dashboard
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow from Gateway / ingress controller
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: customer1
|
||||
ports:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
- port: 8001
|
||||
protocol: TCP
|
||||
- port: 8002
|
||||
protocol: TCP
|
||||
- port: 8003
|
||||
protocol: TCP
|
||||
# Allow inter-service communication
|
||||
- from:
|
||||
- podSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- trading-data-service
|
||||
- trading-execute-service
|
||||
- trading-news-service
|
||||
- trading-dashboard
|
||||
ports:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
- port: 8001
|
||||
protocol: TCP
|
||||
- port: 8002
|
||||
protocol: TCP
|
||||
- port: 8003
|
||||
protocol: TCP
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- port: 53
|
||||
protocol: UDP
|
||||
- port: 53
|
||||
protocol: TCP
|
||||
# Allow DB access
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
cnpg.io/cluster: hermes-pgdb
|
||||
ports:
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
# Allow Redis access
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: trading-redis
|
||||
ports:
|
||||
- port: 6379
|
||||
protocol: TCP
|
||||
# Allow Kafka access
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: trading-kafka
|
||||
ports:
|
||||
- port: 9092
|
||||
protocol: TCP
|
||||
# Allow inter-service egress
|
||||
- to:
|
||||
- podSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- trading-data-service
|
||||
- trading-execute-service
|
||||
- trading-news-service
|
||||
- trading-dashboard
|
||||
ports:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
- port: 8001
|
||||
protocol: TCP
|
||||
- port: 8002
|
||||
protocol: TCP
|
||||
- port: 8003
|
||||
protocol: TCP
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: trading-news-service
|
||||
namespace: customer1
|
||||
labels:
|
||||
app: trading-news-service
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trading-news-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trading-news-service
|
||||
annotations:
|
||||
checksum/config: trading-news-service-config
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: news-service
|
||||
image: ghcr.io/sirius0xdev/trading-news-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8003
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: trading-news-service-config
|
||||
env:
|
||||
- name: DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: username
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: trading-db-credentials
|
||||
key: password
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8003
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
failureThreshold: 6
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8003
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8003
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trading-news-service
|
||||
namespace: customer1
|
||||
annotations:
|
||||
tailscale.com/expose: "true"
|
||||
tailscale.com/hostname: "trading-news-service"
|
||||
tailscale.com/tags: "tag:k8s-operator"
|
||||
tailscale.com/ports: "http:80"
|
||||
spec:
|
||||
selector:
|
||||
app: trading-news-service
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8003
|
||||
name: http
|
||||
type: ClusterIP
|
||||
53
apps/base/customer1/trading-platform/routes/http-routes.yaml
Normal file
53
apps/base/customer1/trading-platform/routes/http-routes.yaml
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: trading-dashboard-route
|
||||
namespace: customer1
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: external-http-gateway
|
||||
hostnames:
|
||||
- "sirius-sec.com"
|
||||
- "www.sirius-sec.com"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /trade
|
||||
backendRefs:
|
||||
- name: trading-dashboard-svc
|
||||
port: 80
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: trading-api-routes
|
||||
namespace: customer1
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: external-http-gateway
|
||||
hostnames:
|
||||
- "sirius-sec.com"
|
||||
- "www.sirius-sec.com"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api/data
|
||||
backendRefs:
|
||||
- name: trading-data-service
|
||||
port: 80
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api/execute
|
||||
backendRefs:
|
||||
- name: trading-execute-service
|
||||
port: 80
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api/news
|
||||
backendRefs:
|
||||
- name: trading-news-service
|
||||
port: 80
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- http-routes.yaml
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- trading-secrets.yaml
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
apiVersion: ENC[AES256_GCM,data:j4g=,iv:Bb3E3dbyD1MUIsthCltT2rRNNorduAL7QmPG8oRy31g=,tag:htxjh/00z6RGQNNyKCUviw==,type:str]
|
||||
kind: ENC[AES256_GCM,data:k3FRKBzN,iv:Pvtu7bnGWQNl9pkjtU8GpHjpeg00oFXatf3jxxtQEpw=,tag:zj/yAy/DpCfLO7MdH3hiMA==,type:str]
|
||||
metadata:
|
||||
name: ENC[AES256_GCM,data:ZpbqQd2YyEfnugJ27JVAmqBf8Q7m75B0,iv:4njbS+2AYJuxzNERSOjOH8wmoI1KM0ocUT7OgeoGEgo=,tag:spwlHcpeQM0G8O3VPHoDOg==,type:str]
|
||||
namespace: ENC[AES256_GCM,data:4ErEXcBaI8Yp,iv:IKHgZ6Gm5X21Atnnm2xOFU11IgSfw5X5Wdnl25EDyOI=,tag:znkdsNDkIb4mxBY4yJbX9g==,type:str]
|
||||
type: ENC[AES256_GCM,data:dd7uKLw+,iv:qRkV8K+ytp55rLGNIP1lG2yZ+LENt/FkdDiWzi/1tik=,tag:aUWQ+ZOQS7/hXcnceCyrTQ==,type:str]
|
||||
stringData:
|
||||
#ENC[AES256_GCM,data:Xol7d8ednDll9VKfZ62jZRdARcmz8UJ/6ovDaw8OHrPb72aUdA==,iv:TvGk+LiK0+maCioF5daeWDTNKOSRA5pBFf9PgKL/9Z4=,tag:34kee3TQNsCdIpyEtE12mA==,type:comment]
|
||||
news-api-key: ENC[AES256_GCM,data:eNMLhs55u3bwVqD4l2tQhgq1+wp/9rCa,iv:7BjlJqgJbg6BqdXxNphnIWKA/LYFZJc3qqJ360/EteY=,tag:hs5vfj+zP9OCq2tDucItIg==,type:str]
|
||||
market-data-api-key: ENC[AES256_GCM,data:ol3aAC9ijFcFUo7jEVQv7mKjCLpUXBuaVThwRzG/fQ==,iv:YouuIdmj6aK0tuYJtDuiOt91gnUtK2xdshVZxy+gCH4=,tag:MAs8mS/+ndC8AYdI+WdFcA==,type:str]
|
||||
#ENC[AES256_GCM,data:Si0AKl5/sWrYDNSYiC35iD7vtvP9CzAb,iv:cyBrgR5cFSta+bPdyyCUXrKH68Hi84UbGFqiWskQb7s=,tag:w9+sotMjBTuyfcGYIHfN+w==,type:comment]
|
||||
service-auth-token: ENC[AES256_GCM,data:NCu/mBKdGIFNXTA5n7M53UXjMaZy9UdzImC90GPU,iv:JPLeNfTDWV3VLbVIUidL6w1IrJN09LTGIyPn0tJlj90=,tag:RIzC8FfGXBmE2PRZzgaAww==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age1uuxf066xuuqgvjppxfcmqkwfcufnwp3wcwnl9h20g9k4l8nkw9jsaungf7
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFTzBrN3V5elJmNjNGZ28y
|
||||
Q1JOQUt5eURqSFZNZkJUNWMrV1NTZEFiYkgwCnlDSTFYTW8zcU02M0NJdXZjYSti
|
||||
Ylh0bWpJd0k2MWt6VjNNTUlNU0pTUVUKLS0tIENHUEU4VElXbC96bXBGRmo3QXpQ
|
||||
ZkxxUDRubGt0dnRoQXVtS2xFSnhTRkUKs+rcKiZvgA7mffGo7GkkFL4vWnTIGAIn
|
||||
RXwlbDNPEhiK+6lh/TgkV2CYXDBt1Hwfk4fzhZknYjY3Psp0ufvY2Q==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-05-21T04:08:04Z"
|
||||
mac: ENC[AES256_GCM,data:EEuPQ1n7qAab7xkQYNt4rxzNy+u6PSYn+hFUTv3ZwmKbMHW7zQY3BgkwalDVrTC4ZNOLy3tGjVDB6v0KXmwXiXwvYL0Y17h8zRiU4id+zQl+oeZTMCFoUZ5Piz69DxO06cMaZF7+6K+9uQ0JLkZsnY3hb82xKAKbl9E/MFdvr6s=,iv:ldIAz5IKNFnbvcNpzo9qX6n0evix7tsLcTPiouB8lfk=,tag:KXDYrz4vfXkWH0cUHsOUdw==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.9.4
|
||||
15
apps/base/osint-dashboard/Chart.yaml
Normal file
15
apps/base/osint-dashboard/Chart.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# OSINT Dashboard — Helm Chart
|
||||
apiVersion: v2
|
||||
name: osint-dashboard
|
||||
description: Real-time geospatial OSINT dashboard infrastructure
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
||||
keywords:
|
||||
- osint
|
||||
- dashboard
|
||||
- geospatial
|
||||
- real-time
|
||||
maintainers:
|
||||
- name: sec-ops
|
||||
email: sec-ops@osint-dashboard.local
|
||||
67
apps/base/osint-dashboard/templates/_helpers.tpl
Normal file
67
apps/base/osint-dashboard/templates/_helpers.tpl
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "osint-dashboard.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "osint-dashboard.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 64 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 64 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 64 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "osint-dashboard.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "osint-dashboard.labels" -}}
|
||||
helm.sh/chart: {{ include "osint-dashboard.chart" . }}
|
||||
{{ include "osint-dashboard.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "osint-dashboard.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "osint-dashboard.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Namespace labels
|
||||
*/}}
|
||||
{{- define "osint-dashboard.namespaceLabels" -}}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "osint-dashboard.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "osint-dashboard.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
47
apps/base/osint-dashboard/templates/ingress/ingress.yaml
Normal file
47
apps/base/osint-dashboard/templates/ingress/ingress.yaml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: {{ $host.host | replace "." "-" | trunc 50 | trimSuffix "-" }}
|
||||
namespace: {{ $.Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: external-http-gateway
|
||||
hostnames:
|
||||
- "{{ $host.host }}"
|
||||
rules:
|
||||
{{- range $rule := $host.paths }}
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: {{ $rule.path }}
|
||||
backendRefs:
|
||||
- name: dashboard-web
|
||||
port: 3000
|
||||
weight: 100
|
||||
{{- end }}
|
||||
---
|
||||
{{- end }}
|
||||
|
||||
# TLS Certificate resources
|
||||
{{- range $tls := .Values.ingress.tls }}
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ $tls.secretName }}
|
||||
namespace: {{ $.Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
secretName: {{ $tls.secretName }}
|
||||
issuerRef:
|
||||
name: {{ $.Values.ingress.certManager.clusterIssuerName }}
|
||||
kind: ClusterIssuer
|
||||
dnsNames:
|
||||
{{- toYaml $tls.hosts | nindent 4 }}
|
||||
---
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
{{- if .Values.minio.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: minio-buckets-init
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
containers:
|
||||
- name: mc
|
||||
image: "{{ .Values.minio.image.repository }}:{{ .Values.minio.image.tag }}"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ .Values.minio.credentialsSecret }}
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
args:
|
||||
- |
|
||||
# Wait for MinIO to be ready
|
||||
until curl -sf http://minio:{{ .Values.minio.ports.api }}/minio/health/live; do
|
||||
echo "Waiting for MinIO..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Configure mc alias
|
||||
mc alias set myminio http://minio:{{ .Values.minio.ports.api }} $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD
|
||||
|
||||
# Create buckets
|
||||
mc mb --ignore-existing myminio/osint-video-clips
|
||||
mc mb --ignore-existing myminio/osint-satellite-tiles
|
||||
mc mb --ignore-existing myminio/osint-data-dumps
|
||||
|
||||
echo "MinIO buckets initialized successfully"
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "64Mi"
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{{- if .Values.minio.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ .Values.minio.credentialsSecret }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
# SOPS will encrypt this
|
||||
type: Opaque
|
||||
stringData:
|
||||
MINIO_ROOT_USER: CHANGE_ME_USE_SOPS
|
||||
MINIO_ROOT_PASSWORD: CHANGE_ME_USE_SOPS
|
||||
{{- end }}
|
||||
49
apps/base/osint-dashboard/templates/minio/service.yaml
Normal file
49
apps/base/osint-dashboard/templates/minio/service.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{{- if .Values.minio.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: minio
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.minio.ports.api }}
|
||||
targetPort: {{ .Values.minio.ports.api }}
|
||||
protocol: TCP
|
||||
name: api
|
||||
- port: {{ .Values.minio.ports.console }}
|
||||
targetPort: {{ .Values.minio.ports.console }}
|
||||
protocol: TCP
|
||||
name: console
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: object-storage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: minio-headless
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: {{ .Values.minio.ports.api }}
|
||||
targetPort: {{ .Values.minio.ports.api }}
|
||||
protocol: TCP
|
||||
name: api
|
||||
- port: {{ .Values.minio.ports.console }}
|
||||
targetPort: {{ .Values.minio.ports.console }}
|
||||
protocol: TCP
|
||||
name: console
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: object-storage
|
||||
{{- end }}
|
||||
84
apps/base/osint-dashboard/templates/minio/statefulset.yaml
Normal file
84
apps/base/osint-dashboard/templates/minio/statefulset.yaml
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{{- if .Values.minio.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: minio
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
spec:
|
||||
serviceName: minio-headless
|
||||
replicas: {{ .Values.minio.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: object-storage
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "{{ .Values.minio.ports.api }}"
|
||||
prometheus.io/path: "/minio/v2/metrics/cluster"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: minio
|
||||
image: "{{ .Values.minio.image.repository }}:{{ .Values.minio.image.tag }}"
|
||||
ports:
|
||||
- name: api
|
||||
containerPort: {{ .Values.minio.ports.api }}
|
||||
- name: console
|
||||
containerPort: {{ .Values.minio.ports.console }}
|
||||
resources:
|
||||
{{- toYaml .Values.minio.resources | nindent 12 }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ .Values.minio.credentialsSecret }}
|
||||
env:
|
||||
- name: MINIO_SERVER_URL
|
||||
value: "http://minio.{{ .Values.namespace }}.svc:{{ .Values.minio.ports.api }}"
|
||||
args:
|
||||
- server
|
||||
- "--console-address"
|
||||
- ":{{ .Values.minio.ports.console }}"
|
||||
- "--address"
|
||||
- ":{{ .Values.minio.ports.api }}"
|
||||
# Distributed mode: all 4 pods
|
||||
- "http://minio-{0...3}.minio-headless.{{ .Values.namespace }}.svc/data"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /minio/health/live
|
||||
port: api
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /minio/health/live
|
||||
port: api
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.minio.storage.size }}
|
||||
storageClassName: {{ .Values.minio.storage.storageClass }}
|
||||
{{- end }}
|
||||
134
apps/base/osint-dashboard/templates/monitoring/alertmanager.yaml
Normal file
134
apps/base/osint-dashboard/templates/monitoring/alertmanager.yaml
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
{{- if .Values.monitoring.enabled }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: alertmanager-config
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
data:
|
||||
alertmanager.yml: |
|
||||
global:
|
||||
resolve_timeout: 5m
|
||||
|
||||
route:
|
||||
group_by: ['alertname', 'namespace']
|
||||
group_wait: 30s
|
||||
group_interval: 5m
|
||||
repeat_interval: 4h
|
||||
receiver: 'default'
|
||||
routes:
|
||||
- match:
|
||||
severity: critical
|
||||
receiver: 'pager'
|
||||
repeat_interval: 1h
|
||||
- match:
|
||||
severity: warning
|
||||
receiver: 'slack'
|
||||
|
||||
receivers:
|
||||
- name: 'default'
|
||||
email_configs:
|
||||
- to: CHANGE_ME_USE_SOPS
|
||||
from: monitoring@{{ .Values.monitoring.defaultEmailDomain }}
|
||||
smarthost: CHANGE_ME_USE_SOPS
|
||||
auth_username: CHANGE_ME_USE_SOPS
|
||||
auth_password: CHANGE_ME_USE_SOPS
|
||||
|
||||
- name: 'pager'
|
||||
webhook_configs:
|
||||
- url: CHANGE_ME_USE_SOPS
|
||||
send_resolved: true
|
||||
|
||||
- name: 'slack'
|
||||
slack_configs:
|
||||
- api_url: CHANGE_ME_USE_SOPS
|
||||
channel: '#osint-alerts'
|
||||
send_resolved: true
|
||||
title: '{{ .GroupLabels.alertname }}'
|
||||
text: >-
|
||||
{{ range .Alerts }}
|
||||
*Alert:* {{ .Labels.alertname }}
|
||||
*Severity:* {{ .Labels.severity }}
|
||||
*Summary:* {{ .Annotations.summary }}
|
||||
{{ end }}
|
||||
|
||||
inhibit_rules:
|
||||
- source_match:
|
||||
severity: 'critical'
|
||||
target_match:
|
||||
severity: 'warning'
|
||||
equal: ['alertname', 'namespace']
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: alertmanager
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
fsGroup: 65534
|
||||
containers:
|
||||
- name: alertmanager
|
||||
image: "{{ .Values.monitoring.alertmanager.image.repository }}:{{ .Values.monitoring.alertmanager.image.tag }}"
|
||||
ports:
|
||||
- containerPort: {{ .Values.monitoring.alertmanager.port }}
|
||||
name: web
|
||||
args:
|
||||
- "--config.file=/etc/alertmanager/alertmanager.yml"
|
||||
- "--storage.path=/alertmanager"
|
||||
resources:
|
||||
{{- toYaml .Values.monitoring.alertmanager.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/alertmanager
|
||||
- name: data
|
||||
mountPath: /alertmanager
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: alertmanager-config
|
||||
strategy:
|
||||
type: Recreate
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: alertmanager
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.monitoring.alertmanager.port }}
|
||||
targetPort: web
|
||||
protocol: TCP
|
||||
name: web
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: monitoring
|
||||
{{- end }}
|
||||
158
apps/base/osint-dashboard/templates/monitoring/grafana.yaml
Normal file
158
apps/base/osint-dashboard/templates/monitoring/grafana.yaml
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
{{- if .Values.monitoring.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: grafana-admin-secret
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
type: Opaque
|
||||
stringData:
|
||||
admin-user: CHANGE_ME_USE_SOPS
|
||||
admin-password: CHANGE_ME_USE_SOPS
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-datasources
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
data:
|
||||
datasources.yaml: |
|
||||
apiVersion: 1
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
url: http://prometheus:{{ .Values.monitoring.prometheus.port }}
|
||||
isDefault: true
|
||||
editable: true
|
||||
- name: PostgreSQL
|
||||
type: postgres
|
||||
access: proxy
|
||||
url: postgresql-rw.{{ .Values.namespace }}.svc:5432
|
||||
database: osint
|
||||
user: grafana
|
||||
secureJsonData:
|
||||
password: CHANGE_ME_USE_SOPS
|
||||
jsonData:
|
||||
tlsAuth: false
|
||||
sslmode: disable
|
||||
postgresVersion: 1600
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboards
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
data:
|
||||
dashboard-providers.yaml: |
|
||||
apiVersion: 1
|
||||
providers:
|
||||
- name: 'default'
|
||||
orgId: 1
|
||||
folder: ''
|
||||
type: file
|
||||
disableDeletion: false
|
||||
editable: true
|
||||
options:
|
||||
path: /var/lib/grafana/dashboards
|
||||
foldersFromFilesStructure: false
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "3000"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 472 # grafana
|
||||
fsGroup: 472
|
||||
containers:
|
||||
- name: grafana
|
||||
image: "{{ .Values.monitoring.grafana.image.repository }}:{{ .Values.monitoring.grafana.image.tag }}"
|
||||
ports:
|
||||
- containerPort: {{ .Values.monitoring.grafana.port }}
|
||||
name: web
|
||||
env:
|
||||
- name: GF_SECURITY_ADMIN_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: grafana-admin-secret
|
||||
key: admin-user
|
||||
- name: GF_SECURITY_ADMIN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: grafana-admin-secret
|
||||
key: admin-password
|
||||
- name: GF_SERVER_ROOT_URL
|
||||
value: "https://grafana.{{ .Values.monitoring.grafana.hostname }}"
|
||||
- name: GF_AUTH_ANONYMOUS_ENABLED
|
||||
value: "false"
|
||||
resources:
|
||||
{{- toYaml .Values.monitoring.grafana.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: datasources
|
||||
mountPath: /etc/grafana/provisioning/datasources
|
||||
- name: dashboards-config
|
||||
mountPath: /etc/grafana/provisioning/dashboards
|
||||
- name: data
|
||||
mountPath: /var/lib/grafana
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: datasources
|
||||
configMap:
|
||||
name: grafana-datasources
|
||||
- name: dashboards-config
|
||||
configMap:
|
||||
name: grafana-dashboards
|
||||
strategy:
|
||||
type: Recreate
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.monitoring.grafana.port }}
|
||||
targetPort: web
|
||||
protocol: TCP
|
||||
name: web
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: monitoring
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
{{- if .Values.monitoring.enabled }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: prometheus-config
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
data:
|
||||
prometheus.yml: |
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
scrape_timeout: 10s
|
||||
|
||||
rule_files:
|
||||
- /etc/prometheus/rules/*.yml
|
||||
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets:
|
||||
- alertmanager:{{ .Values.monitoring.alertmanager.port }}
|
||||
|
||||
scrape_configs:
|
||||
# Prometheus self-monitoring
|
||||
- job_name: prometheus
|
||||
static_configs:
|
||||
- targets: [localhost:9090]
|
||||
|
||||
# PostgreSQL (Postgres Exporter)
|
||||
- job_name: postgresql
|
||||
static_configs:
|
||||
- targets:
|
||||
{{- range $i := until $.Values.monitoring.postgresql.exporter.replicas }}
|
||||
- postgresql-{{ $i }}.postgresql-rw.{{ $.Values.namespace }}.svc:9187
|
||||
{{- end }}
|
||||
|
||||
# NATS JetStream
|
||||
- job_name: nats
|
||||
static_configs:
|
||||
- targets:
|
||||
{{- range $i := until $.Values.nats.replicaCount }}
|
||||
- nats-{{ $i }}.nats-cluster.{{ $.Values.namespace }}.svc:8222
|
||||
{{- end }}
|
||||
|
||||
# Redis
|
||||
- job_name: redis
|
||||
static_configs:
|
||||
- targets:
|
||||
{{- range $i := until $.Values.redis.replicaCount }}
|
||||
- redis-{{ $i }}.redis-cluster.{{ $.Values.namespace }}.svc:9121
|
||||
{{- end }}
|
||||
|
||||
# MinIO
|
||||
- job_name: minio
|
||||
metrics_path: /minio/v2/metrics/cluster
|
||||
static_configs:
|
||||
- targets:
|
||||
{{- range $i := until $.Values.minio.replicaCount }}
|
||||
- minio-{{ $i }}.minio-headless.{{ $.Values.namespace }}.svc:9000
|
||||
{{- end }}
|
||||
|
||||
# Kafka Exporter
|
||||
- job_name: kafka
|
||||
static_configs:
|
||||
- targets: [kafka-exporter:9308]
|
||||
|
||||
# Dashboard web app
|
||||
- job_name: dashboard-web
|
||||
static_configs:
|
||||
- targets: [dashboard-web:3000]
|
||||
|
||||
# Dashboard API
|
||||
- job_name: dashboard-api
|
||||
static_configs:
|
||||
- targets: [dashboard-api:4000]
|
||||
|
||||
# Auto-discover via pod annotations
|
||||
- job_name: kubernetes-pods
|
||||
kubernetes_sd_configs:
|
||||
- role: pod
|
||||
namespaces:
|
||||
own: false
|
||||
names:
|
||||
- {{ .Values.namespace }}
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
|
||||
action: keep
|
||||
regex: "true"
|
||||
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
|
||||
action: replace
|
||||
target_label: __metrics_path__
|
||||
regex: (.+)
|
||||
- source_labels:
|
||||
- __meta_kubernetes_pod_annotation_prometheus_io_port
|
||||
- __meta_kubernetes_pod_ip
|
||||
action: replace
|
||||
regex: ([\d+]);([\d.]+)
|
||||
replacement: $2:$1
|
||||
target_label: __address__
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: prometheus-rules
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
data:
|
||||
osint-alerts.yml: |
|
||||
groups:
|
||||
- name: osint-dashboard-alerts
|
||||
rules:
|
||||
- alert: HighErrorRate
|
||||
expr: sum(rate(http_requests_total{status=~"5..",namespace="{{ .Values.namespace }}"}[5m])) / sum(rate(http_requests_total{namespace="{{ .Values.namespace }}"}[5m])) > 0.05
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "High error rate detected (>{{ 5 }}%) on {{ $labels.job }}"
|
||||
|
||||
- alert: PodCrashLooping
|
||||
expr: rate(kube_pod_container_status_restarts_total{namespace="{{ .Values.namespace }}"}[15m]) * 60 * 5 > 0
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Pod {{ $labels.pod }} is crash looping"
|
||||
|
||||
- alert: HighLatency
|
||||
expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{namespace="{{ .Values.namespace }}"}[5m])) by (le, job)) > 2
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "P95 latency above 2s for {{ $labels.job }}"
|
||||
|
||||
- alert: DiskSpaceLow
|
||||
expr: kubelet_volume_stats_available_bytes{namespace="{{ .Values.namespace }}"}/kubelet_volume_stats_capacity_bytes{namespace="{{ .Values.namespace }}"} < 0.1
|
||||
for: 10m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Disk space below 10% on {{ $labels.persistentvolumeclaim }}"
|
||||
|
||||
- alert: PostgreSQLConnectionSaturation
|
||||
expr: pg_stat_activity_count{datname="osint",state="active"}/pg_settings_max_connections > 0.8
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "PostgreSQL connection pool >80% saturated"
|
||||
|
||||
- alert: NATSJetStreamStoreFull
|
||||
expr: jetstream_store_disk_bytes / jetstream_config_max_store_bytes > 0.85
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "NATS JetStream disk usage >85%"
|
||||
|
||||
- alert: RedisMemoryHigh
|
||||
expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.9
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Redis memory usage >90%"
|
||||
|
||||
- alert: MinIOOffline
|
||||
expr: up{job="minio"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "MinIO node {{ $labels.instance }} is offline"
|
||||
|
||||
- alert: KafkaLagHigh
|
||||
expr: kafka_consumer_group_lag > 10000
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Kafka consumer lag >10k messages for group {{ $labels.group }}"
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
{{- if .Values.monitoring.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "9090"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534 # nobody
|
||||
fsGroup: 65534
|
||||
serviceAccountName: prometheus
|
||||
containers:
|
||||
- name: prometheus
|
||||
image: "{{ .Values.monitoring.prometheus.image.repository }}:{{ .Values.monitoring.prometheus.image.tag }}"
|
||||
ports:
|
||||
- containerPort: {{ .Values.monitoring.prometheus.port }}
|
||||
name: web
|
||||
args:
|
||||
- "--config.file=/etc/prometheus/prometheus.yml"
|
||||
- "--storage.tsdb.path=/prometheus"
|
||||
- "--storage.tsdb.retention.time={{ .Values.monitoring.prometheus.retention }}"
|
||||
- "--storage.tsdb.retention.size={{ .Values.monitoring.prometheus.retentionSize }}"
|
||||
- "--web.enable-lifecycle"
|
||||
- "--web.enable-admin-api"
|
||||
resources:
|
||||
{{- toYaml .Values.monitoring.prometheus.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/prometheus
|
||||
- name: rules
|
||||
mountPath: /etc/prometheus/rules
|
||||
- name: data
|
||||
mountPath: /prometheus
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: prometheus-config
|
||||
- name: rules
|
||||
configMap:
|
||||
name: prometheus-rules
|
||||
strategy:
|
||||
type: Recreate
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "9090"
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.monitoring.prometheus.port }}
|
||||
targetPort: web
|
||||
protocol: TCP
|
||||
name: web
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: monitoring
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "services", "endpoints", "configmaps"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: monitoring
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: prometheus
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: prometheus
|
||||
namespace: {{ .Values.namespace }}
|
||||
{{- end }}
|
||||
49
apps/base/osint-dashboard/templates/namespace.yaml
Normal file
49
apps/base/osint-dashboard/templates/namespace.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.namespaceLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/part-of: osint-dashboard
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: osint-dashboard-role
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "services", "configmaps", "secrets", "persistentvolumeclaims"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["deployments", "statefulsets"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["batch"]
|
||||
resources: ["jobs", "cronjobs"]
|
||||
verbs: ["get", "list", "watch", "create", "update"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: osint-dashboard-rolebinding
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: osint-dashboard-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "osint-dashboard.serviceAccountName" . }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "osint-dashboard.serviceAccountName" . }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
{{- if .Values.nats.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: nats-jetstream-init
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
containers:
|
||||
- name: nats-box
|
||||
image: "{{ .Values.nats.image.repository }}:{{ .Values.nats.image.tag }}"
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
args:
|
||||
- |
|
||||
# Wait for NATS to be ready
|
||||
until nats-server -version > /dev/null 2>&1 || curl -sf http://nats:{{ .Values.nats.ports.monitor }}/healthz; do
|
||||
echo "Waiting for NATS..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Download nats CLI
|
||||
curl -fsSL https://github.com/nats-io/natscli/releases/latest/download/nats-linux-amd64 -o /tmp/nats
|
||||
chmod +x /tmp/nats
|
||||
|
||||
# Create JetStream stream for events
|
||||
/tmp/nats stream add events \
|
||||
--subjects=events.gdelt,events.rss,events.social,events.earthquake,events.disaster,events.weather,events.fire,events.satellite,events.new,events.alert \
|
||||
--retention=interests \
|
||||
--max-consumers=-1 \
|
||||
--max-msgs=1000000 \
|
||||
--max-bytes=1GB \
|
||||
--discard=old \
|
||||
--storage=file \
|
||||
--replicas=3 \
|
||||
--server=nats://nats:{{ .Values.nats.ports.client }} || echo "events stream already exists"
|
||||
|
||||
# Create JetStream stream for alerts
|
||||
/tmp/nats stream add alerts \
|
||||
--subjects=alerts.camera_offline,alerts.new \
|
||||
--retention=interests \
|
||||
--max-consumers=-1 \
|
||||
--max-msgs=100000 \
|
||||
--discard=old \
|
||||
--storage=file \
|
||||
--replicas=3 \
|
||||
--server=nats://nats:{{ .Values.nats.ports.client }} || echo "alerts stream already exists"
|
||||
|
||||
# Create JetStream stream for video
|
||||
/tmp/nats stream add video \
|
||||
--subjects="video.status.>","video.record.>" \
|
||||
--retention=limits \
|
||||
--max-consumers=-1 \
|
||||
--max-msgs=50000 \
|
||||
--discard=old \
|
||||
--storage=file \
|
||||
--replicas=3 \
|
||||
--server=nats://nats:{{ .Values.nats.ports.client }} || echo "video stream already exists"
|
||||
|
||||
echo "JetStream subjects initialized successfully"
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "64Mi"
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
{{- end }}
|
||||
60
apps/base/osint-dashboard/templates/nats/service.yaml
Normal file
60
apps/base/osint-dashboard/templates/nats/service.yaml
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
{{- if .Values.nats.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nats
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.nats.ports.client }}
|
||||
targetPort: {{ .Values.nats.ports.client }}
|
||||
protocol: TCP
|
||||
name: client
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: message-broker
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nats-ws
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.nats.ports.websocket }}
|
||||
targetPort: {{ .Values.nats.ports.websocket }}
|
||||
protocol: TCP
|
||||
name: websocket
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: message-broker
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nats-cluster
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: {{ .Values.nats.ports.cluster }}
|
||||
targetPort: {{ .Values.nats.ports.cluster }}
|
||||
protocol: TCP
|
||||
name: cluster
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: message-broker
|
||||
{{- end }}
|
||||
130
apps/base/osint-dashboard/templates/nats/statefulset.yaml
Normal file
130
apps/base/osint-dashboard/templates/nats/statefulset.yaml
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
{{- if .Values.nats.enabled }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: nats-config
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
data:
|
||||
nats-server.conf: |
|
||||
port: {{ .Values.nats.ports.client }}
|
||||
server_name: "osint-nats-${HOSTNAME}"
|
||||
|
||||
# Cluster
|
||||
cluster {
|
||||
port: {{ .Values.nats.ports.cluster }}
|
||||
routes: [
|
||||
nats-route://nats-0.nats-cluster.{{ .Values.namespace }}.svc:{{ .Values.nats.ports.cluster }},
|
||||
nats-route://nats-1.nats-cluster.{{ .Values.namespace }}.svc:{{ .Values.nats.ports.cluster }},
|
||||
nats-route://nats-2.nats-cluster.{{ .Values.namespace }}.svc:{{ .Values.nats.ports.cluster }}
|
||||
]
|
||||
cluster_advertise: "nats-${HOSTNAME}.nats-cluster.{{ .Values.namespace }}.svc:{{ .Values.nats.ports.cluster }}"
|
||||
}
|
||||
|
||||
# JetStream
|
||||
jetstream {
|
||||
store_dir: "{{ .Values.nats.jetstream.fileStore }}"
|
||||
max_mem_store: {{ .Values.nats.jetstream.maxMemory }}
|
||||
max_file_store: {{ .Values.nats.storage.size }}
|
||||
}
|
||||
|
||||
# Monitoring
|
||||
monitor: {{ .Values.nats.ports.monitor }}
|
||||
|
||||
# WebSocket
|
||||
websocket {
|
||||
port: {{ .Values.nats.ports.websocket }}
|
||||
no_tls: true
|
||||
}
|
||||
|
||||
# Logging
|
||||
logtime: true
|
||||
log_file: /var/log/nats/nats.log
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: nats
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
spec:
|
||||
serviceName: nats-cluster
|
||||
replicas: {{ .Values.nats.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: message-broker
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "{{ .Values.nats.ports.monitor }}"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: nats
|
||||
image: "{{ .Values.nats.image.repository }}:{{ .Values.nats.image.tag }}"
|
||||
ports:
|
||||
- name: client
|
||||
containerPort: {{ .Values.nats.ports.client }}
|
||||
- name: cluster
|
||||
containerPort: {{ .Values.nats.ports.cluster }}
|
||||
- name: monitor
|
||||
containerPort: {{ .Values.nats.ports.monitor }}
|
||||
- name: websocket
|
||||
containerPort: {{ .Values.nats.ports.websocket }}
|
||||
resources:
|
||||
{{- toYaml .Values.nats.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/nats-config
|
||||
- name: data
|
||||
mountPath: {{ .Values.nats.jetstream.fileStore }}
|
||||
- name: logs
|
||||
mountPath: /var/log/nats
|
||||
args:
|
||||
- "-c"
|
||||
- "/etc/nats-config/nats-server.conf"
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: monitor
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: monitor
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: nats-config
|
||||
- name: logs
|
||||
emptyDir: {}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.nats.storage.size }}
|
||||
storageClassName: {{ .Values.nats.storage.storageClass }}
|
||||
{{- end }}
|
||||
152
apps/base/osint-dashboard/templates/postgresql/cluster.yaml
Normal file
152
apps/base/osint-dashboard/templates/postgresql/cluster.yaml
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
{{- if .Values.postgresql.enabled }}
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: {{ .Values.postgresql.clusterName }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
spec:
|
||||
instances: {{ .Values.postgresql.instances }}
|
||||
imageName: {{ .Values.postgresql.imageName }}
|
||||
storage:
|
||||
size: {{ .Values.postgresql.storage.size }}
|
||||
storageClass: {{ .Values.postgresql.storage.storageClass }}
|
||||
resources:
|
||||
{{- toYaml .Values.postgresql.resources | nindent 4 }}
|
||||
# PostGIS + TimescaleDB extensions via shared_preload_libraries
|
||||
postgresql:
|
||||
shared_preload_libraries:
|
||||
- pggis
|
||||
- timescaledb
|
||||
parameters:
|
||||
max_connections: "500"
|
||||
shared_buffers: "2GB"
|
||||
effective_cache_size: "6GB"
|
||||
maintenance_work_mem: "512MB"
|
||||
work_mem: "16MB"
|
||||
wal_buffers: "64MB"
|
||||
random_page_cost: "1.1"
|
||||
effective_io_concurrency: "200"
|
||||
default_statistics_target: "200"
|
||||
max_parallel_workers_per_gather: "4"
|
||||
bootstrap:
|
||||
initdb:
|
||||
database: osint
|
||||
owner: osint_admin
|
||||
secret:
|
||||
name: {{ .Values.postgresql.credentialsSecret }}
|
||||
postInitializationSQL:
|
||||
# Install PostGIS extension
|
||||
- >-
|
||||
CREATE EXTENSION IF NOT EXISTS postgis;
|
||||
- >-
|
||||
CREATE EXTENSION IF NOT EXISTS postgis_raster;
|
||||
- >-
|
||||
CREATE EXTENSION IF NOT EXISTS postgis_topology;
|
||||
# Install TimescaleDB extension
|
||||
- >-
|
||||
CREATE EXTENSION IF NOT EXISTS timescaledb;
|
||||
# Create hypertable for events
|
||||
- >-
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
time TIMESTAMPTZ NOT NULL,
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
source TEXT NOT NULL,
|
||||
event_type TEXT,
|
||||
title TEXT,
|
||||
description TEXT,
|
||||
location GEOGRAPHY(POINT, 4326),
|
||||
severity INT DEFAULT 0,
|
||||
tags TEXT[],
|
||||
raw_data JSONB,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
- >-
|
||||
SELECT create_hypertable('events', 'time', if_not_exists => TRUE);
|
||||
- >-
|
||||
CREATE INDEX IF NOT EXISTS events_loc_idx ON events USING GIST (location);
|
||||
- >-
|
||||
CREATE INDEX IF NOT EXISTS events_time_idx ON events (time DESC);
|
||||
# Create sources reference table
|
||||
- >-
|
||||
CREATE TABLE IF NOT EXISTS sources (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
config JSONB,
|
||||
active BOOLEAN DEFAULT TRUE
|
||||
);
|
||||
# Create video_feeds table
|
||||
- >-
|
||||
CREATE TABLE IF NOT EXISTS video_feeds (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
rtsp_url TEXT NOT NULL,
|
||||
zlm_stream_key TEXT NOT NULL,
|
||||
location GEOGRAPHY(POINT, 4326),
|
||||
active BOOLEAN DEFAULT TRUE,
|
||||
last_heartbeat TIMESTAMPTZ
|
||||
);
|
||||
managed:
|
||||
roles:
|
||||
- name: osint_admin
|
||||
ensure: present
|
||||
login: true
|
||||
passwordSecret:
|
||||
name: {{ .Values.postgresql.credentialsSecret }}
|
||||
- name: osint_reader
|
||||
ensure: present
|
||||
login: true
|
||||
passwordSecret:
|
||||
name: osint-pg-reader-credentials
|
||||
backup:
|
||||
barmanObjectStore:
|
||||
destinationPath: "{{ .Values.postgresql.backup.bucket }}"
|
||||
googleCredentials:
|
||||
gkeEnvironment: true
|
||||
wal:
|
||||
compression: gzip
|
||||
data:
|
||||
compression: gzip
|
||||
jobs: 2
|
||||
retentionPolicy: {{ .Values.postgresql.backup.retentionPolicy }}
|
||||
target: primary
|
||||
monitoring:
|
||||
customQueries:
|
||||
- query: >-
|
||||
SELECT relname, schemaname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch
|
||||
FROM pg_stat_user_tables WHERE schemaname = 'public';
|
||||
metrics:
|
||||
- relname:
|
||||
usage: "LABEL"
|
||||
description: "Table name"
|
||||
- schemaname:
|
||||
usage: "LABEL"
|
||||
description: "Schema name"
|
||||
- seq_scan:
|
||||
usage: "GAUGE"
|
||||
description: "Number of sequential scans"
|
||||
- seq_tup_read:
|
||||
usage: "GAUGE"
|
||||
description: "Number of tuples read"
|
||||
- idx_scan:
|
||||
usage: "GAUGE"
|
||||
description: "Number of index scans"
|
||||
- idx_tup_fetch:
|
||||
usage: "GAUGE"
|
||||
description: "Number of tuples fetched via index"
|
||||
affinity:
|
||||
enablePodAntiAffinity: true
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: topology.kubernetes.io/zone
|
||||
whenUnsatisfiable: DoNotSchedule
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
postgresql operator: {{ .Values.postgresql.clusterName }}
|
||||
nodesAutoRemediationChecks:
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 10
|
||||
timeoutSeconds: 5
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{{- if .Values.postgresql.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ .Values.postgresql.credentialsSecret }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
# SOPS will encrypt this - use 'sops --encrypt --in-place' after generation
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: osint_admin
|
||||
password: CHANGE_ME_USE_SOPS
|
||||
connection_string: "postgresql://osint_admin:CHANGE_ME_USE_SOPS@{{ .Values.postgresql.clusterName }}.{{ .Values.namespace }}.svc:5432/osint?sslmode=require"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: osint-pg-reader-credentials
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: osint_reader
|
||||
password: CHANGE_ME_USE_SOPS
|
||||
connection_string: "postgresql://osint_reader:CHANGE_ME_USE_SOPS@{{ .Values.postgresql.clusterName }}.{{ .Values.namespace }}.svc:5432/osint?sslmode=require"
|
||||
{{- end }}
|
||||
18
apps/base/osint-dashboard/templates/postgresql/service.yaml
Normal file
18
apps/base/osint-dashboard/templates/postgresql/service.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{{- if .Values.postgresql.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Values.postgresql.clusterName }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: postgresql
|
||||
protocol: TCP
|
||||
name: postgresql
|
||||
selector:
|
||||
postgresql operator: {{ .Values.postgresql.clusterName }}
|
||||
{{- end }}
|
||||
70
apps/base/osint-dashboard/templates/redis/configmap.yaml
Normal file
70
apps/base/osint-dashboard/templates/redis/configmap.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
{{- if .Values.redis.enabled }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: redis-config
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
data:
|
||||
redis.conf: |
|
||||
bind 0.0.0.0
|
||||
port {{ .Values.redis.ports.redis }}
|
||||
appendonly yes
|
||||
appendfilename "appendonly.aof"
|
||||
dir /data
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
maxmemory-policy allkeys-lru
|
||||
# Require authentication
|
||||
requirepass CHANGE_ME_USE_SOPS
|
||||
masterauth CHANGE_ME_USE_SOPS
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: redis-sentinel-config
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
data:
|
||||
sentinel.conf: |
|
||||
port {{ .Values.redis.ports.sentinel }}
|
||||
sentinel monitor osint-redis-master redis-master.{{ .Values.namespace }}.svc {{ .Values.redis.ports.redis }} 2
|
||||
sentinel auth-pass osint-redis-master CHANGE_ME_USE_SOPS
|
||||
sentinel down-after-milliseconds osint-redis-master 5000
|
||||
sentinel failover-timeout osint-redis-master 30000
|
||||
sentinel parallel-syncs osint-redis-master 1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: redis-scripts
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
data:
|
||||
init-sentinel.sh: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Copy sentinel config and update it with current master info
|
||||
cp /etc/redis-sentinel/sentinel.conf /tmp/sentinel.conf
|
||||
# Sentinel will auto-discover master from other sentinels
|
||||
exec redis-sentinel /tmp/sentinel.conf --loglevel notice
|
||||
redis.sh: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
REDIS_PORT={{ .Values.redis.ports.redis }}
|
||||
REDIS_PASSWORD="CHANGE_ME_USE_SOPS"
|
||||
|
||||
if [ "${REDIS_ROLE}" = "master" ]; then
|
||||
exec redis-server /etc/redis/redis.conf
|
||||
else
|
||||
# Replica: find master and replicate
|
||||
MASTER_HOST="redis-master.{{ .Values.namespace }}.svc"
|
||||
exec redis-server /etc/redis/redis.conf --replicaof ${MASTER_HOST} ${REDIS_PORT}
|
||||
fi
|
||||
{{- end }}
|
||||
61
apps/base/osint-dashboard/templates/redis/service.yaml
Normal file
61
apps/base/osint-dashboard/templates/redis/service.yaml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{{- if .Values.redis.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-master
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: redis
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.redis.ports.redis }}
|
||||
targetPort: {{ .Values.redis.ports.redis }}
|
||||
protocol: TCP
|
||||
name: redis
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: master
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-replica
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: redis
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.redis.ports.redis }}
|
||||
targetPort: {{ .Values.redis.ports.redis }}
|
||||
protocol: TCP
|
||||
name: redis
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: replica
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-sentinel
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: redis
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.redis.ports.sentinel }}
|
||||
targetPort: {{ .Values.redis.ports.sentinel }}
|
||||
protocol: TCP
|
||||
name: sentinel
|
||||
selector:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: sentinel
|
||||
{{- end }}
|
||||
210
apps/base/osint-dashboard/templates/redis/statefulset.yaml
Normal file
210
apps/base/osint-dashboard/templates/redis/statefulset.yaml
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
{{- if .Values.redis.enabled }}
|
||||
# Redis Master
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis-master
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: master
|
||||
spec:
|
||||
serviceName: redis-master
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: master
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: master
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "9121"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999
|
||||
fsGroup: 999
|
||||
containers:
|
||||
- name: redis
|
||||
image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}"
|
||||
ports:
|
||||
- name: redis
|
||||
containerPort: {{ .Values.redis.ports.redis }}
|
||||
resources:
|
||||
{{- toYaml .Values.redis.master.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/redis
|
||||
- name: data
|
||||
mountPath: /data
|
||||
args: ["redis-server", "/etc/redis/redis.conf"]
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
# Sentinel sidecar on master
|
||||
- name: sentinel
|
||||
image: "{{ .Values.redis.sentinel.image.repository }}:{{ .Values.redis.sentinel.image.tag }}"
|
||||
ports:
|
||||
- name: sentinel
|
||||
containerPort: {{ .Values.redis.ports.sentinel }}
|
||||
resources:
|
||||
{{- toYaml .Values.redis.sentinel.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: sentinel-config
|
||||
mountPath: /etc/redis-sentinel
|
||||
command: ["/bin/bash", "/etc/redis-scripts/init-sentinel.sh"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: redis-config
|
||||
- name: sentinel-config
|
||||
configMap:
|
||||
name: redis-sentinel-config
|
||||
- name: scripts
|
||||
configMap:
|
||||
name: redis-scripts
|
||||
defaultMode: 0755
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.redis.master.storage.size }}
|
||||
storageClassName: {{ .Values.redis.master.storage.storageClass }}
|
||||
---
|
||||
# Redis Replicas
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis-replica
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: replica
|
||||
spec:
|
||||
serviceName: redis-replica
|
||||
replicas: {{ .Values.redis.replica.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: replica
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "osint-dashboard.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: redis
|
||||
redis-role: replica
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "9121"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999
|
||||
fsGroup: 999
|
||||
containers:
|
||||
- name: redis
|
||||
image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}"
|
||||
ports:
|
||||
- name: redis
|
||||
containerPort: {{ .Values.redis.ports.redis }}
|
||||
resources:
|
||||
{{- toYaml .Values.redis.replica.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/redis
|
||||
- name: data
|
||||
mountPath: /data
|
||||
env:
|
||||
- name: REDIS_ROLE
|
||||
value: "replica"
|
||||
command: ["/bin/bash", "/etc/redis-scripts/redis.sh"]
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
# Sentinel sidecar on replicas
|
||||
- name: sentinel
|
||||
image: "{{ .Values.redis.sentinel.image.repository }}:{{ .Values.redis.sentinel.image.tag }}"
|
||||
ports:
|
||||
- name: sentinel
|
||||
containerPort: {{ .Values.redis.ports.sentinel }}
|
||||
resources:
|
||||
{{- toYaml .Values.redis.sentinel.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: sentinel-config
|
||||
mountPath: /etc/redis-sentinel
|
||||
command: ["/bin/bash", "/etc/redis-scripts/init-sentinel.sh"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: redis-config
|
||||
- name: sentinel-config
|
||||
configMap:
|
||||
name: redis-sentinel-config
|
||||
- name: scripts
|
||||
configMap:
|
||||
name: redis-scripts
|
||||
defaultMode: 0755
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.redis.replica.storage.size }}
|
||||
storageClassName: {{ .Values.redis.replica.storage.storageClass }}
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: dashboard-web-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: web
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow from ingress controller / Gateway API
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: ingress-nginx
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 3000
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow to API
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: api
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4000
|
||||
# Allow to external APIs (GDelt, satellite providers)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: dashboard-api-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: api
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow from web frontend
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: web
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4000
|
||||
# Allow from ingress controller / Gateway API
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: ingress-nginx
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4000
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow to PostgreSQL
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: database
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
# Allow to Redis
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: cache
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.redis.ports.redis }}
|
||||
# Allow to NATS
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: messaging
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.nats.ports.client }}
|
||||
# Allow to MinIO
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: object-storage
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.minio.ports.api }}
|
||||
# Allow to external APIs (GDelt, etc.)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
{{- if .Values.networkPolicies.defaultDeny }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-all
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: minio-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: object-storage
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow from dashboard services
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.minio.ports.api }}
|
||||
# Allow console access (internal)
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.minio.ports.console }}
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow to other MinIO pods (distributed replication)
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: object-storage
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.minio.ports.api }}
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: monitoring-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: monitoring
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow Grafana web access
|
||||
- from: []
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.monitoring.grafana.port }}
|
||||
- protocol: TCP
|
||||
port: {{ .Values.monitoring.prometheus.port }}
|
||||
- protocol: TCP
|
||||
port: {{ .Values.monitoring.alertmanager.port }}
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow scraping all OSINT pods
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 9090
|
||||
- protocol: TCP
|
||||
port: 9093
|
||||
- protocol: TCP
|
||||
port: 3000
|
||||
- protocol: TCP
|
||||
port: 9187 # postgres-exporter
|
||||
- protocol: TCP
|
||||
port: 9121 # redis-exporter
|
||||
- protocol: TCP
|
||||
port: 8222 # nats-monitor
|
||||
- protocol: TCP
|
||||
port: 9000 # minio
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: nats-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: messaging
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow client connections from dashboard services
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.nats.ports.client }}
|
||||
# Allow cluster communication
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: messaging
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.nats.ports.cluster }}
|
||||
# Allow monitoring
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/component: monitoring
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.nats.ports.monitor }}
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow cluster communication
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: messaging
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.nats.ports.cluster }}
|
||||
- protocol: TCP
|
||||
port: {{ .Values.nats.ports.client }}
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: postgresql-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: database
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow from dashboard API and workers
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/component: prometheus-exporter
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
# Allow from CNPG cluster peers (replication)
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: database
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow to other PG replicas (replication)
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: database
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
{{- end }}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{{- if .Values.networkPolicies.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: redis-netpol
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
{{- include "osint-dashboard.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: security
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: cache
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow from dashboard services
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.redis.ports.redis }}
|
||||
# Allow sentinel from dashboard + other sentinels
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.redis.ports.sentinel }}
|
||||
egress:
|
||||
# Allow DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow to other Redis pods (replication)
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: osint-dashboard
|
||||
app.kubernetes.io/component: cache
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.redis.ports.redis }}
|
||||
- protocol: TCP
|
||||
port: {{ .Values.redis.ports.sentinel }}
|
||||
{{- end }}
|
||||
360
apps/base/osint-dashboard/values.yaml
Normal file
360
apps/base/osint-dashboard/values.yaml
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
# OSINT Dashboard — Helm Values
|
||||
# Default values for development/staging. Override with values-prod.yaml for production.
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
# Namespace
|
||||
namespace: customer1
|
||||
|
||||
# Global security context
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
fsGroup: 1000
|
||||
|
||||
# Resource defaults
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# ============================================================
|
||||
# PostgreSQL (using CNPG — CloudNativePG, already installed)
|
||||
# ============================================================
|
||||
postgresql:
|
||||
enabled: true
|
||||
clusterName: osint-pgdb
|
||||
instances: 3
|
||||
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||
# Custom image with PostGIS + TimescaleDB
|
||||
# Use CNPG bootstrap to create extensions
|
||||
storage:
|
||||
size: 200Gi
|
||||
storageClass: premium-rwo
|
||||
resources:
|
||||
requests:
|
||||
cpu: "2"
|
||||
memory: 4Gi
|
||||
limits:
|
||||
cpu: "4"
|
||||
memory: 8Gi
|
||||
extensions:
|
||||
- postgis
|
||||
- timescaledb
|
||||
backup:
|
||||
retentionPolicy: "30d"
|
||||
bucket: "gs://osint-dashboard-db-backup/"
|
||||
credentialsSecret: osint-pg-credentials
|
||||
|
||||
# ============================================================
|
||||
# NATS JetStream (3 replicas, persistent)
|
||||
# ============================================================
|
||||
nats:
|
||||
enabled: true
|
||||
replicaCount: 3
|
||||
image:
|
||||
repository: nats
|
||||
tag: "2.10.18-alpine"
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
storage:
|
||||
size: 50Gi
|
||||
storageClass: premium-rwo
|
||||
jetstream:
|
||||
enabled: true
|
||||
maxMemory: 2Gi
|
||||
fileStore: /data/jetstream
|
||||
ports:
|
||||
client: 4222
|
||||
cluster: 6222
|
||||
monitor: 8222
|
||||
websocket: 8080
|
||||
# JetStream subjects schema
|
||||
subjects:
|
||||
streams:
|
||||
- name: events
|
||||
subjects:
|
||||
- events.gdelt
|
||||
- events.rss
|
||||
- events.social
|
||||
- events.earthquake
|
||||
- events.disaster
|
||||
- events.weather
|
||||
- events.fire
|
||||
- events.satellite
|
||||
- events.new
|
||||
- events.alert
|
||||
retention: interests
|
||||
maxConsumers: -1
|
||||
maxMsgs: 1000000
|
||||
maxBytes: 1073741824 # 1GB
|
||||
discard: old
|
||||
- name: alerts
|
||||
subjects:
|
||||
- alerts.camera_offline
|
||||
- alerts.new
|
||||
retention: interests
|
||||
maxConsumers: -1
|
||||
maxMsgs: 100000
|
||||
discard: old
|
||||
- name: video
|
||||
subjects:
|
||||
- "video.status.>"
|
||||
- "video.record.>"
|
||||
retention: limits
|
||||
maxConsumers: -1
|
||||
maxMsgs: 50000
|
||||
discard: old
|
||||
|
||||
# ============================================================
|
||||
# Redis Sentinel (1 primary + 2 replicas)
|
||||
# ============================================================
|
||||
redis:
|
||||
enabled: true
|
||||
image:
|
||||
repository: redis
|
||||
tag: "7.4-alpine"
|
||||
sentinel:
|
||||
image:
|
||||
repository: redis
|
||||
tag: "7.4-alpine"
|
||||
master:
|
||||
replicaCount: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
storage:
|
||||
size: 20Gi
|
||||
storageClass: premium-rwo
|
||||
replica:
|
||||
replicaCount: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: "250m"
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: 512Mi
|
||||
storage:
|
||||
size: 20Gi
|
||||
storageClass: premium-rwo
|
||||
sentinel:
|
||||
replicaCount: 3
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: "250m"
|
||||
memory: 256Mi
|
||||
ports:
|
||||
redis: 6379
|
||||
sentinel: 26379
|
||||
|
||||
# ============================================================
|
||||
# MinIO (4 replicas, distributed mode)
|
||||
# ============================================================
|
||||
minio:
|
||||
enabled: true
|
||||
image:
|
||||
repository: quay.io/minio/minio
|
||||
tag: "latest"
|
||||
replicaCount: 4
|
||||
mode: distributed
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: 1Gi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 2Gi
|
||||
storage:
|
||||
size: 500Gi
|
||||
storageClass: premium-rwo
|
||||
buckets:
|
||||
- name: osint-video-clips
|
||||
policy: none
|
||||
- name: osint-satellite-tiles
|
||||
policy: none
|
||||
- name: osint-data-dumps
|
||||
policy: none
|
||||
credentialsSecret: osint-minio-credentials
|
||||
ports:
|
||||
api: 9000
|
||||
console: 9001
|
||||
|
||||
# ============================================================
|
||||
# NGINX Ingress Controller + cert-manager
|
||||
# ============================================================
|
||||
ingress:
|
||||
enabled: true
|
||||
# Use existing cert-manager cluster issuer
|
||||
certManager:
|
||||
enabled: true
|
||||
clusterIssuerName: letsencrypt-prod
|
||||
hosts:
|
||||
- host: dashboard.siriusdevops.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
- host: api.siriusdevops.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
- host: ws.siriusdevops.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: osint-dashboard-tls
|
||||
hosts:
|
||||
- dashboard.siriusdevops.com
|
||||
- secretName: osint-api-tls
|
||||
hosts:
|
||||
- api.siriusdevops.com
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||
# WebSocket support
|
||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||
|
||||
# ============================================================
|
||||
# Monitoring (Prometheus + Grafana + Alertmanager)
|
||||
# ============================================================
|
||||
monitoring:
|
||||
enabled: true
|
||||
defaultEmailDomain: siriusdevops.com
|
||||
|
||||
prometheus:
|
||||
image:
|
||||
repository: prom/prometheus
|
||||
tag: "v2.53.0"
|
||||
port: 9090
|
||||
retention: "30d"
|
||||
retentionSize: "50GB"
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: 2Gi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 4Gi
|
||||
|
||||
alertmanager:
|
||||
image:
|
||||
repository: prom/alertmanager
|
||||
tag: "v0.27.0"
|
||||
port: 9093
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: "250m"
|
||||
memory: 256Mi
|
||||
|
||||
grafana:
|
||||
image:
|
||||
repository: grafana/grafana
|
||||
tag: "11.2.0"
|
||||
port: 3000
|
||||
hostname: grafana.siriusdevops.com
|
||||
resources:
|
||||
requests:
|
||||
cpu: "200m"
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: 512Mi
|
||||
|
||||
exporters:
|
||||
nats:
|
||||
enabled: true
|
||||
image:
|
||||
repository: natsio/prometheus-nats-exporter
|
||||
tag: "0.14.0"
|
||||
postgresql:
|
||||
enabled: true
|
||||
image:
|
||||
repository: prometheuscommunity/postgres-exporter
|
||||
tag: "0.15.0"
|
||||
exporter:
|
||||
replicas: 3
|
||||
redis:
|
||||
enabled: true
|
||||
image:
|
||||
repository: oliver006/redis_exporter
|
||||
tag: "v1.58.0"
|
||||
minio:
|
||||
enabled: true
|
||||
# MinIO has built-in metrics at /minio/v2/metrics/cluster
|
||||
|
||||
grafanaDashboards:
|
||||
- osint-overview
|
||||
- nats-jetstream
|
||||
- postgresql-performance
|
||||
- redis-sentinel
|
||||
- minio-storage
|
||||
|
||||
# ============================================================
|
||||
# CI/CD
|
||||
# ============================================================
|
||||
cicd:
|
||||
enabled: true
|
||||
registry: gcr.io/devops-lab-cluster
|
||||
previewEnvironments: true
|
||||
|
||||
# ============================================================
|
||||
# Network Policies
|
||||
# ============================================================
|
||||
networkPolicies:
|
||||
enabled: true
|
||||
# Default deny all ingress/egress, then allow specific traffic
|
||||
defaultDeny: true
|
||||
|
||||
# ============================================================
|
||||
# Frontend (placeholder — T3 will fill this in)
|
||||
# ============================================================
|
||||
frontend:
|
||||
enabled: false
|
||||
replicaCount: 3
|
||||
image:
|
||||
repository: gcr.io/devops-lab-cluster/osint-dashboard-web
|
||||
tag: latest
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: 512Mi
|
||||
|
||||
# ============================================================
|
||||
# API (placeholder — T2 will fill this in)
|
||||
# ============================================================
|
||||
api:
|
||||
enabled: false
|
||||
replicaCount: 3
|
||||
image:
|
||||
repository: gcr.io/devops-lab-cluster/osint-dashboard-api
|
||||
tag: latest
|
||||
resources:
|
||||
requests:
|
||||
cpu: "200m"
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
|
|
@ -11,3 +11,4 @@ resources:
|
|||
- ../../base/customer1/hermes-db/
|
||||
- ../../base/customer1/trade-dashboard/
|
||||
- ../../base/customer1/siriusdevops-db/
|
||||
- ../../base/customer1/trading-platform/
|
||||
|
|
|
|||
53
apps/staging/osint-dashboard/kustomization.yaml
Normal file
53
apps/staging/osint-dashboard/kustomization.yaml
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
# Reference the Helm chart base
|
||||
helmCharts:
|
||||
- name: osint-dashboard
|
||||
repository:
|
||||
name: osint-dashboard-local
|
||||
type: oci
|
||||
url: oci://gcr.io/devops-lab-cluster/charts
|
||||
version: "0.1.0"
|
||||
releaseName: osint-dashboard
|
||||
namespace: customer1
|
||||
includeCRDs: true
|
||||
|
||||
# Or use plain Kustomize overlay on the base templates
|
||||
resources:
|
||||
- ../../base/osint-dashboard/templates/namespace.yaml
|
||||
|
||||
# Namespace override
|
||||
namespace: customer1
|
||||
|
||||
# Common labels
|
||||
commonLabels:
|
||||
app.kubernetes.io/managed-by: flux
|
||||
app.kubernetes.io/part-of: osint-dashboard
|
||||
|
||||
# Patches for staging environment
|
||||
patches:
|
||||
# Override replica counts for staging
|
||||
- patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: postgresql
|
||||
spec:
|
||||
replicas: 2
|
||||
target:
|
||||
kind: StatefulSet
|
||||
name: postgresql.*
|
||||
|
||||
# Reduce storage for staging
|
||||
- patch: |-
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: data
|
||||
spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Gi
|
||||
target:
|
||||
kind: PersistentVolumeClaim
|
||||
Loading…
Add table
Reference in a new issue