diff --git a/apolo/configmaps/configmap-coredns.yaml b/apolo/configmaps/configmap-coredns.yaml
index 8b94610..f4e5657 100644
--- a/apolo/configmaps/configmap-coredns.yaml
+++ b/apolo/configmaps/configmap-coredns.yaml
@@ -18,6 +18,13 @@ data:
192.168.200.13 muc.chat.apolo.c2et.net
192.168.200.12 streaming.apolo.c2et.net
192.168.200.14 meeting.apolo.c2et.net
+
+ # === ARGOS (videovigilancia) ===
+ 192.168.200.15 mqtt.argos.interna
+ 192.168.200.16 mediamtx.argos.interna
+ 192.168.200.10 s3.argos.interna
+ 192.168.200.10 minio.argos.interna
+ 192.168.200.10 panel.argos.c2et.net
fallthrough
}
forward . /etc/resolv.conf
diff --git a/argos/certs/certificate-argos-panel.yaml b/argos/certs/certificate-argos-panel.yaml
new file mode 100644
index 0000000..002bfee
--- /dev/null
+++ b/argos/certs/certificate-argos-panel.yaml
@@ -0,0 +1,12 @@
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: panel-argos-cert
+ namespace: argos-core
+spec:
+ secretName: panel-argos-tls
+ issuerRef:
+ name: letsencrypt-prod
+ kind: ClusterIssuer
+ dnsNames:
+ - panel.argos.c2et.net
diff --git a/argos/configmaps/configmap-mediamtx.yaml b/argos/configmaps/configmap-mediamtx.yaml
new file mode 100644
index 0000000..3285b67
--- /dev/null
+++ b/argos/configmaps/configmap-mediamtx.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: mediamtx-config
+ namespace: argos-core
+data:
+ mediamtx.yml: |
+ logLevel: info
+ rtsp: yes
+ rtmp: no
+ hls: no
+ webrtc: yes
+ paths:
+ all:
+ sourceOnDemand: yes
diff --git a/argos/configmaps/configmap-mosquitto.yaml b/argos/configmaps/configmap-mosquitto.yaml
new file mode 100644
index 0000000..9e55849
--- /dev/null
+++ b/argos/configmaps/configmap-mosquitto.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: mosquitto-conf
+ namespace: argos-core
+data:
+ mosquitto.conf: |
+ listener 1883 0.0.0.0
+ allow_anonymous true
diff --git a/argos/configmaps/configmap-orchestrator.yaml b/argos/configmaps/configmap-orchestrator.yaml
new file mode 100644
index 0000000..76f0d7f
--- /dev/null
+++ b/argos/configmaps/configmap-orchestrator.yaml
@@ -0,0 +1,156 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: argos-orchestrator-config
+ namespace: argos-core
+data:
+ settings.yaml: |
+ mqtt:
+ host: mqtt.argos.interna
+ port: 1883
+ topic: frigate/events
+ client_id: argos-core
+ minio:
+ bucket: argos
+ region: us-east-1
+ edges:
+ - name: rpi01
+ base_url: http://10.20.0.10:5000 # URL del Frigate del edge (VPN). 5000 por defecto.
+ api_token: "" # si usas auth, ponlo aquí
+ cameras:
+ - name: cam1
+ rtsp_main: rtsp://10.20.0.10:8554/cam1_main
+ path_mtx: cam1 # para abrir live en MediaMTX: /?path=cam1
+ app.py: |
+ import os, json, time, datetime, sqlite3, subprocess, yaml, requests
+ from pathlib import Path
+ from urllib.parse import urljoin
+ import paho.mqtt.client as mqtt
+ from minio import Minio
+
+ CFG_PATH="/app/settings.yaml"
+ DB_PATH="/data/argos.db"
+ TMP="/tmp"
+ with open(CFG_PATH,"r") as f:
+ CFG=yaml.safe_load(f)
+
+ # Map quick-lookup: camera -> (edge, cfg)
+ CAM_MAP={}
+ for e in CFG.get("edges", []):
+ for c in e.get("cameras", []):
+ CAM_MAP[c["name"]]=(e, c)
+
+ # MinIO
+ mc=Minio(os.getenv("MINIO_ENDPOINT","s3.argos.interna"),
+ access_key=os.getenv("MINIO_ACCESS_KEY"),
+ secret_key=os.getenv("MINIO_SECRET_KEY"),
+ secure=os.getenv("MINIO_SECURE","false").lower()=="true")
+ BUCKET=CFG["minio"]["bucket"]
+ if not mc.bucket_exists(BUCKET): mc.make_bucket(BUCKET)
+
+ # DB
+ Path("/data").mkdir(parents=True, exist_ok=True)
+ con=sqlite3.connect(DB_PATH, check_same_thread=False)
+ cur=con.cursor()
+ cur.execute("""CREATE TABLE IF NOT EXISTS events(
+ id TEXT PRIMARY KEY, ts INTEGER, edge TEXT, camera TEXT, label TEXT,
+ s3url TEXT, thumb_s3 TEXT
+ )""")
+ con.commit()
+
+ def upload_file(local_path, key, content_type):
+ mc.fput_object(BUCKET, key, local_path, content_type=content_type)
+ return f"s3://{BUCKET}/{key}"
+
+ def fetch_frigate_clip(edge_cfg, ev_id):
+ """ Descarga el clip nativo de Frigate si existe """
+ base=edge_cfg["base_url"]
+ url=urljoin(base, f"/api/events/{ev_id}/clip")
+ headers={}
+ if edge_cfg.get("api_token"):
+ headers["Authorization"]=f"Bearer {edge_cfg['api_token']}"
+ r=requests.get(url, headers=headers, stream=True, timeout=30)
+ if r.status_code!=200: return None
+ tmp=f"{TMP}/{ev_id}.mp4"
+ with open(tmp,"wb") as f:
+ for chunk in r.iter_content(1<<20):
+ if chunk: f.write(chunk)
+ return tmp
+
+ def fetch_frigate_thumb(edge_cfg, ev_id):
+ base=edge_cfg["base_url"]
+ url=urljoin(base, f"/api/events/{ev_id}/thumbnail.jpg")
+ headers={}
+ if edge_cfg.get("api_token"):
+ headers["Authorization"]=f"Bearer {edge_cfg['api_token']}"
+ r=requests.get(url, headers=headers, timeout=10)
+ if r.status_code!=200: return None
+ tmp=f"{TMP}/{ev_id}.jpg"
+ with open(tmp,"wb") as f: f.write(r.content)
+ return tmp
+
+ def record_rtsp(rtsp_url, seconds=30):
+ tmp=f"{TMP}/rtsp_{int(time.time())}.mp4"
+ cmd=["ffmpeg","-nostdin","-y","-rtsp_transport","tcp","-i",rtsp_url,"-t",str(seconds),"-c","copy",tmp]
+ try:
+ subprocess.run(cmd, check=True)
+ return tmp
+ except Exception as e:
+ print("FFmpeg fallback failed:", e)
+ return None
+
+ def on_message(client, userdata, msg):
+ try:
+ payload=json.loads(msg.payload.decode("utf-8"))
+ except Exception as e:
+ print("Bad JSON", e); return
+
+ ev_type=payload.get("type")
+ after=payload.get("after") or {}
+ ev_id=after.get("id") or payload.get("id")
+ cam=after.get("camera") or payload.get("camera")
+ label=after.get("label") or payload.get("label","")
+
+ if ev_type!="new" or not cam or not ev_id: return
+ if cam not in CAM_MAP:
+ print("Unknown camera:", cam); return
+
+ edge_cfg, cam_cfg = CAM_MAP[cam]
+ ts=int(time.time())
+ print(f"[ARGOS] {ev_id} {cam} → try Frigate clip")
+ path_local = fetch_frigate_clip(edge_cfg, ev_id)
+ if not path_local:
+ print(f"[ARGOS] {ev_id} no native clip, fallback RTSP")
+ path_local = record_rtsp(cam_cfg["rtsp_main"], seconds=30)
+ if not path_local:
+ print(f"[ARGOS] {ev_id} failed recording"); return
+
+ # upload clip
+ date=datetime.datetime.utcfromtimestamp(ts)
+ key=f"{cam}/{date.year:04d}/{date.month:02d}/{date.day:02d}/{ts}_{ev_id}.mp4"
+ s3url=upload_file(path_local, key, "video/mp4")
+ try: os.remove(path_local)
+ except: pass
+
+ # thumbnail
+ thumb_local = fetch_frigate_thumb(edge_cfg, ev_id)
+ thumb_s3=None
+ if thumb_local:
+ tkey=f"{cam}/thumbs/{ts}_{ev_id}.jpg"
+ thumb_s3=upload_file(thumb_local, tkey, "image/jpeg")
+ try: os.remove(thumb_local)
+ except: pass
+
+ cur.execute("INSERT OR REPLACE INTO events(id, ts, edge, camera, label, s3url, thumb_s3) VALUES (?,?,?,?,?,?,?)",
+ (ev_id, ts, edge_cfg["name"], cam, label, s3url, thumb_s3))
+ con.commit()
+ print(f"[ARGOS] stored {s3url}")
+
+ def main():
+ m=mqtt.Client(client_id=CFG["mqtt"]["client_id"], clean_session=True)
+ m.connect(CFG["mqtt"]["host"], CFG["mqtt"]["port"], keepalive=60)
+ m.subscribe(CFG["mqtt"]["topic"])
+ m.on_message=on_message
+ m.loop_forever()
+
+ if __name__=="__main__": main()
diff --git a/argos/configmaps/configmap-panel.yaml b/argos/configmaps/configmap-panel.yaml
new file mode 100644
index 0000000..4404c50
--- /dev/null
+++ b/argos/configmaps/configmap-panel.yaml
@@ -0,0 +1,87 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: argos-panel-config
+ namespace: argos-core
+data:
+ app.py: |
+ import os, sqlite3, time
+ from fastapi import FastAPI, HTTPException
+ from fastapi.responses import HTMLResponse
+ from minio import Minio
+ from urllib.parse import urlparse
+
+ DB="/data/argos.db"
+ mc=Minio(os.getenv("MINIO_ENDPOINT","s3.argos.interna"),
+ access_key=os.getenv("MINIO_ACCESS_KEY"),
+ secret_key=os.getenv("MINIO_SECRET_KEY"),
+ secure=os.getenv("MINIO_SECURE","false").lower()=="true")
+ app=FastAPI()
+
+ def rows(limit=100, camera=None, since=None):
+ q="SELECT id, ts, edge, camera, label, s3url, thumb_s3 FROM events"
+ cond=[]; args=[]
+ if camera: cond.append("camera=?"); args.append(camera)
+ if since: cond.append("ts>=?"); args.append(int(since))
+ if cond: q+=" WHERE "+ " AND ".join(cond)
+ q+=" ORDER BY ts DESC LIMIT ?"; args.append(limit)
+ con=sqlite3.connect(DB); cur=con.cursor()
+ cur.execute(q, tuple(args)); r=cur.fetchall(); con.close()
+ return r
+
+ @app.get("/api/events")
+ def api_events(limit:int=100, camera:str=None, since:int=None):
+ return [dict(id=i, ts=t, edge=e, camera=c, label=l or "", s3url=s, thumb=th or "")
+ for (i,t,e,c,l,s,th) in rows(limit,camera,since)]
+
+ @app.get("/api/url/{event_id}")
+ def presign(event_id: str, expires: int = 600):
+ con=sqlite3.connect(DB); cur=con.cursor()
+ cur.execute("SELECT s3url FROM events WHERE id=?", (event_id,))
+ row=cur.fetchone(); con.close()
+ if not row: raise HTTPException(404, "Not found")
+ s3url=row[0]; p=urlparse(s3url); b=p.netloc; k=p.path.lstrip("/")
+ return {"url": mc.presigned_get_object(b, k, expires=expires)}
+
+ @app.get("/", response_class=HTMLResponse)
+ def index():
+ return """
+
ARGOS Panel
+
+ ARGOS – Alarmas
+
+
+
+ """
diff --git a/argos/deployments/deploy-mediamtx.yaml b/argos/deployments/deploy-mediamtx.yaml
new file mode 100644
index 0000000..a92fd19
--- /dev/null
+++ b/argos/deployments/deploy-mediamtx.yaml
@@ -0,0 +1,34 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mediamtx
+ namespace: argos-core
+spec:
+ replicas: 1
+ selector: { matchLabels: { app: mediamtx } }
+ template:
+ metadata: { labels: { app: mediamtx } }
+ spec:
+ hostNetwork: true
+ dnsPolicy: ClusterFirstWithHostNet
+ containers:
+ - name: mediamtx
+ image: bluenviron/mediamtx:1.14.0
+ command: ["/bin/sh","-c"]
+ args:
+ - |
+ set -e
+ ulimit -n 1048576
+ exec mediamtx /config/mediamtx.yml
+ volumeMounts:
+ - name: cfg
+ mountPath: /config
+ ports:
+ - containerPort: 8554 # RTSP
+ - containerPort: 8189 # SRT
+ - containerPort: 8889 # WHIP
+ - containerPort: 8880 # HTTP/API
+ volumes:
+ - name: cfg
+ configMap:
+ name: mediamtx-config
diff --git a/argos/deployments/deploy-minio.yaml b/argos/deployments/deploy-minio.yaml
new file mode 100644
index 0000000..09a4f70
--- /dev/null
+++ b/argos/deployments/deploy-minio.yaml
@@ -0,0 +1,27 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: minio
+ namespace: argos-core
+spec:
+ replicas: 1
+ selector: { matchLabels: { app: minio } }
+ template:
+ metadata: { labels: { app: minio } }
+ spec:
+ containers:
+ - name: minio
+ image: quay.io/minio/minio:latest
+ args: ["server", "/data", "--console-address", ":9001"]
+ envFrom:
+ - secretRef: { name: minio-creds }
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
+ volumeMounts:
+ - name: data
+ mountPath: /data
+ volumes:
+ - name: data
+ persistentVolumeClaim:
+ claimName: minio-data
diff --git a/argos/deployments/deploy-mosquitto.yaml b/argos/deployments/deploy-mosquitto.yaml
new file mode 100644
index 0000000..a82eb87
--- /dev/null
+++ b/argos/deployments/deploy-mosquitto.yaml
@@ -0,0 +1,26 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mosquitto
+ namespace: argos-core
+spec:
+ replicas: 1
+ selector: { matchLabels: { app: mosquitto } }
+ template:
+ metadata: { labels: { app: mosquitto } }
+ spec:
+ containers:
+ - name: mosquitto
+ image: harbor.c2et.net/library/eclipse-mosquitto:latest
+ ports:
+ - containerPort: 1883
+ volumeMounts:
+ - name: cfg
+ mountPath: /mosquitto/config
+ volumes:
+ - name: cfg
+ configMap:
+ name: mosquitto-conf
+ items:
+ - key: mosquitto.conf
+ path: mosquitto.conf
diff --git a/argos/deployments/deploy-orchestrator.yaml b/argos/deployments/deploy-orchestrator.yaml
new file mode 100644
index 0000000..0b8df8f
--- /dev/null
+++ b/argos/deployments/deploy-orchestrator.yaml
@@ -0,0 +1,35 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: argos-orchestrator
+ namespace: argos-core
+spec:
+ replicas: 1
+ selector: { matchLabels: { app: argos-orchestrator } }
+ template:
+ metadata: { labels: { app: argos-orchestrator } }
+ spec:
+ containers:
+ - name: orchestrator
+ image: harbor.c2et.net/library/python:3.13.7-slim-bookworm
+ command: ["/bin/sh","-c"]
+ args:
+ - |
+ set -e
+ apt-get update && apt-get install -y --no-install-recommends ffmpeg curl && rm -rf /var/lib/apt/lists/*
+ pip install paho-mqtt minio pyyaml requests
+ python /app/app.py
+ envFrom:
+ - secretRef: { name: argos-orchestrator-secret }
+ volumeMounts:
+ - { name: cfg, mountPath: /app }
+ - { name: data, mountPath: /data }
+ volumes:
+ - name: cfg
+ configMap:
+ name: argos-orchestrator-config
+ items:
+ - { key: app.py, path: app.py }
+ - { key: settings.yaml, path: settings.yaml }
+ - name: data
+ emptyDir: {}
diff --git a/argos/deployments/deploy-panel.yaml b/argos/deployments/deploy-panel.yaml
new file mode 100644
index 0000000..9da5194
--- /dev/null
+++ b/argos/deployments/deploy-panel.yaml
@@ -0,0 +1,34 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: argos-panel
+ namespace: argos-core
+spec:
+ replicas: 1
+ selector: { matchLabels: { app: argos-panel } }
+ template:
+ metadata: { labels: { app: argos-panel } }
+ spec:
+ containers:
+ - name: panel
+ image: docker.io/library/python:3.13.7-slim-bookworm
+ command: ["/bin/sh","-c"]
+ args:
+ - |
+ set -e
+ pip install fastapi uvicorn minio
+ uvicorn app:app --host 0.0.0.0 --port 8000
+ envFrom:
+ - secretRef: { name: argos-panel-secret }
+ volumeMounts:
+ - { name: app, mountPath: /app }
+ - { name: data, mountPath: /data }
+ ports:
+ - containerPort: 8000
+ volumes:
+ - name: app
+ configMap:
+ name: argos-panel-config
+ items: [ { key: app.py, path: app.py } ]
+ - name: data
+ emptyDir: {}
diff --git a/argos/ingress/ingress-minio.yaml b/argos/ingress/ingress-minio.yaml
new file mode 100644
index 0000000..c7365a2
--- /dev/null
+++ b/argos/ingress/ingress-minio.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: minio-ingress
+ namespace: argos-core
+spec:
+ ingressClassName: nginx
+ rules:
+ - host: s3.argos.interna
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: minio
+ port: { number: 9000 }
+ - host: minio.argos.interna
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: minio
+ port: { number: 9001 }
diff --git a/argos/ingress/ingress-panel.yaml b/argos/ingress/ingress-panel.yaml
new file mode 100644
index 0000000..d7095e2
--- /dev/null
+++ b/argos/ingress/ingress-panel.yaml
@@ -0,0 +1,18 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: argos-panel-internal
+ namespace: argos-core
+spec:
+ ingressClassName: nginx-internal
+ rules:
+ - host: panel.argos.c2et.net # mismo FQDN
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service: { name: argos-panel, port: { number: 80 } }
+ tls:
+ - hosts: ["panel.argos.c2et.net"]
+ secretName: panel-argos-tls
diff --git a/argos/kustomization.yaml b/argos/kustomization.yaml
new file mode 100644
index 0000000..ce3752f
--- /dev/null
+++ b/argos/kustomization.yaml
@@ -0,0 +1,48 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+namespace: argos-core
+
+commonLabels:
+ app.kubernetes.io/part-of: argos
+ app.kubernetes.io/managed-by: kustomize
+
+resources:
+ # Namespace y políticas
+ - namespace.yaml
+ - policies/network-policy.yaml
+
+ # ConfigMaps
+ - configmaps/configmap-mediamtx.yaml
+ - configmaps/configmap-mosquitto.yaml
+ - configmaps/configmap-orchestrator.yaml
+ - configmaps/configmap-panel.yaml
+
+ # Secrets
+ - secrets/secret-minio.yaml
+ - secrets/secret-orchestrator.yaml
+ - secrets/secret-panel.yaml
+
+ # Storage
+ - pvc/pvc-minio.yaml
+
+ # Deployments
+ - deployments/deploy-mediamtx.yaml
+ - deployments/deploy-mosquitto.yaml
+ - deployments/deploy-orchestrator.yaml
+ - deployments/deploy-panel.yaml
+ - deployments/deploy-minio.yaml
+
+ # Services
+ - services/argos-panel.yaml
+ - services/svc-mediamtx-tcp.yaml
+ - services/svc-mediamtx-udp.yaml
+ - services/svc-minio.yaml
+ - services/svc-mosquitto.yaml
+
+ # Ingress
+ - ingress/ingress-minio.yaml
+ - ingress/ingress-panel.yaml
+
+ # Certificados (si usas ACME en el externo y compartes el secret)
+ - certs/certificate-argos-panel.yaml
diff --git a/argos/namespace.yaml b/argos/namespace.yaml
new file mode 100644
index 0000000..09836f7
--- /dev/null
+++ b/argos/namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: argos-core
diff --git a/argos/policies/network-policy.yaml b/argos/policies/network-policy.yaml
new file mode 100644
index 0000000..fcf2dae
--- /dev/null
+++ b/argos/policies/network-policy.yaml
@@ -0,0 +1,12 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: allow-from-wg-and-200
+ namespace: argos-core
+spec:
+ podSelector: {}
+ policyTypes: [Ingress]
+ ingress:
+ - from:
+ - ipBlock: { cidr: 192.168.254.0/24 } # WireGuard peers
+ - ipBlock: { cidr: 192.168.200.0/24 } # red 200 (acceso interno/admin)
diff --git a/argos/pvc/pvc-minio.yaml b/argos/pvc/pvc-minio.yaml
new file mode 100644
index 0000000..702c9d0
--- /dev/null
+++ b/argos/pvc/pvc-minio.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: minio-data
+ namespace: argos-core
+spec:
+ storageClassName: ceph-rbd
+ accessModes: ["ReadWriteOnce"]
+ resources:
+ requests:
+ storage: 1Ti # ajusta capacidad
diff --git a/argos/secrets/secret-harbor-cred.yaml b/argos/secrets/secret-harbor-cred.yaml
new file mode 100644
index 0000000..775414c
--- /dev/null
+++ b/argos/secrets/secret-harbor-cred.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+data:
+ .dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IuYzJldC5jb20iOnsidXNlcm5hbWUiOiJ4YXZvciIsInBhc3N3b3JkIjoiTUBuYWJvMjAyNSIsImVtYWlsIjoibm8tcmVwbHlAYzJldC5jb20iLCJhdXRoIjoiZUdGMmIzSTZUVUJ1WVdKdk1qQXlOUT09In19fQ==
+kind: Secret
+metadata:
+ creationTimestamp: null
+ name: harbor-cred
+ namespace: apolo
+type: kubernetes.io/dockerconfigjson
diff --git a/argos/secrets/secret-minio.yaml b/argos/secrets/secret-minio.yaml
new file mode 100644
index 0000000..1fdc2d4
--- /dev/null
+++ b/argos/secrets/secret-minio.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: minio-creds
+ namespace: argos-core
+type: Opaque
+stringData:
+ MINIO_ROOT_USER: admin
+ MINIO_ROOT_PASSWORD: adminadmin123
diff --git a/argos/secrets/secret-orchestrator.yaml b/argos/secrets/secret-orchestrator.yaml
new file mode 100644
index 0000000..bf16a20
--- /dev/null
+++ b/argos/secrets/secret-orchestrator.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: argos-orchestrator-secret
+ namespace: argos-core
+type: Opaque
+stringData:
+ MINIO_ENDPOINT: minio.argos-core.svc.cluster.local:9000
+ MINIO_ACCESS_KEY: admin
+ MINIO_SECRET_KEY: adminadmin123
+ MINIO_SECURE: "false"
diff --git a/argos/secrets/secret-panel.yaml b/argos/secrets/secret-panel.yaml
new file mode 100644
index 0000000..984e984
--- /dev/null
+++ b/argos/secrets/secret-panel.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: argos-panel-secret
+ namespace: argos-core
+type: Opaque
+stringData:
+ MINIO_ENDPOINT: minio.argos-core.svc.cluster.local:9000
+ MINIO_ACCESS_KEY: admin
+ MINIO_SECRET_KEY: adminadmin123
+ MINIO_SECURE: "false"
diff --git a/argos/services/argos-panel.yaml b/argos/services/argos-panel.yaml
new file mode 100644
index 0000000..cc101e9
--- /dev/null
+++ b/argos/services/argos-panel.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: argos-panel
+ namespace: argos-core
+spec:
+ type: ClusterIP
+ selector: { app: argos-panel }
+ ports:
+ - { name: http, port: 80, targetPort: 8000 }
diff --git a/argos/services/svc-mediamtx-tcp.yaml b/argos/services/svc-mediamtx-tcp.yaml
new file mode 100644
index 0000000..3283b6c
--- /dev/null
+++ b/argos/services/svc-mediamtx-tcp.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: mediamtx-tcp
+ namespace: argos-core
+ annotations:
+ metallb.universe.tf/allow-shared-ip: "mediamtx-addr"
+spec:
+ type: LoadBalancer
+ loadBalancerIP: 192.168.200.16
+ selector: { app: mediamtx }
+ ports:
+ - { name: rtsp, port: 8554, targetPort: 8554, protocol: TCP }
+ - { name: http, port: 8880, targetPort: 8880, protocol: TCP }
+ - { name: whip, port: 8889, targetPort: 8889, protocol: TCP }
diff --git a/argos/services/svc-mediamtx-udp.yaml b/argos/services/svc-mediamtx-udp.yaml
new file mode 100644
index 0000000..db0953b
--- /dev/null
+++ b/argos/services/svc-mediamtx-udp.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: mediamtx-udp
+ namespace: argos-core
+ annotations:
+ metallb.universe.tf/allow-shared-ip: "mediamtx-addr"
+spec:
+ type: LoadBalancer
+ loadBalancerIP: 192.168.200.16
+ selector: { app: mediamtx }
+ ports:
+ - { name: srt, port: 8189, targetPort: 8189, protocol: UDP }
diff --git a/argos/services/svc-minio.yaml b/argos/services/svc-minio.yaml
new file mode 100644
index 0000000..29aa80c
--- /dev/null
+++ b/argos/services/svc-minio.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: minio
+ namespace: argos-core
+spec:
+ type: ClusterIP
+ selector: { app: minio }
+ ports:
+ - { name: api, port: 9000, targetPort: 9000, protocol: TCP }
+ - { name: console, port: 9001, targetPort: 9001, protocol: TCP }
diff --git a/argos/services/svc-mosquitto.yaml b/argos/services/svc-mosquitto.yaml
new file mode 100644
index 0000000..72424c2
--- /dev/null
+++ b/argos/services/svc-mosquitto.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: mosquitto
+ namespace: argos-core
+spec:
+ type: LoadBalancer
+ loadBalancerIP: 192.168.200.15
+ selector: { app: mosquitto }
+ ports:
+ - name: mqtt
+ port: 1883
+ targetPort: 1883
+ protocol: TCP
diff --git a/gitea/copypod.yaml b/gitea/copypod.yaml
new file mode 100644
index 0000000..33952be
--- /dev/null
+++ b/gitea/copypod.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Pod
+metadata: { name: loader, namespace: gitea }
+spec:
+ restartPolicy: Never
+ containers:
+ - name: sh
+ image: alpine:latest
+ command: ["sh","-c","sleep 36000"]
+ volumeMounts:
+ - { name: gitea, mountPath: /mnt/gitea }
+ - { name: mysql, mountPath: /mnt/mysql }
+ volumes:
+ - name: gitea
+ persistentVolumeClaim: { claimName: gitea-data }
+ - name: mysql
+ persistentVolumeClaim: { claimName: gitea-db }
diff --git a/gitea/deployments/gitea-db.yaml b/gitea/deployments/gitea-db.yaml
new file mode 100644
index 0000000..e7659af
--- /dev/null
+++ b/gitea/deployments/gitea-db.yaml
@@ -0,0 +1,36 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: gitea-db
+ namespace: gitea
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: gitea-db
+ template:
+ metadata:
+ labels:
+ app: gitea-db
+ spec:
+ containers:
+ - name: mysql
+ image: mysql:8
+ env:
+ - name: MYSQL_ROOT_PASSWORD
+ value: gitea123
+ - name: MYSQL_DATABASE
+ value: gitea
+ - name: MYSQL_USER
+ value: gitea
+ - name: MYSQL_PASSWORD
+ value: gitea123
+ ports:
+ - containerPort: 3306
+ volumeMounts:
+ - name: gitea-db
+ mountPath: /var/lib/mysql
+ volumes:
+ - name: gitea-db
+ persistentVolumeClaim:
+ claimName: gitea-db
diff --git a/gitea/deployments/gitea.yaml b/gitea/deployments/gitea.yaml
new file mode 100644
index 0000000..327d56e
--- /dev/null
+++ b/gitea/deployments/gitea.yaml
@@ -0,0 +1,42 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: gitea
+ namespace: gitea
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: gitea
+ template:
+ metadata:
+ labels:
+ app: gitea
+ spec:
+ containers:
+ - name: gitea
+ image: gitea/gitea:latest
+ ports:
+ - containerPort: 3000
+ env:
+ - name: USER_UID
+ value: "1000"
+ - name: USER_GID
+ value: "1000"
+ - name: GITEA__database__DB_TYPE
+ value: "mysql"
+ - name: GITEA__database__HOST
+ value: "gitea-db:3306"
+ - name: GITEA__database__NAME
+ value: "gitea"
+ - name: GITEA__database__USER
+ value: "gitea"
+ - name: GITEA__database__PASSWD
+ value: "gitea123"
+ volumeMounts:
+ - name: gitea-data
+ mountPath: /data
+ volumes:
+ - name: gitea-data
+ persistentVolumeClaim:
+ claimName: gitea-data
diff --git a/gitea/ingress/ingress.yaml b/gitea/ingress/ingress.yaml
new file mode 100644
index 0000000..480f421
--- /dev/null
+++ b/gitea/ingress/ingress.yaml
@@ -0,0 +1,28 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: gitea
+ namespace: gitea
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+ nginx.ingress.kubernetes.io/ssl-redirect: "false"
+# nginx.ingress.kubernetes.io/proxy-body-size: "20m"
+ nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
+ nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
+spec:
+ ingressClassName: nginx
+ tls:
+ - hosts:
+ - git.c2et.net
+ secretName: gitea-tls
+ rules:
+ - host: git.c2et.net
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: gitea
+ port:
+ number: 3000
diff --git a/gitea/kustomization.yaml b/gitea/kustomization.yaml
new file mode 100644
index 0000000..d55b114
--- /dev/null
+++ b/gitea/kustomization.yaml
@@ -0,0 +1,9 @@
+resources:
+ - namespace.yaml
+ - pvc/gitea-data.yaml
+ - pvc/gitea-db.yaml
+ - deployments/gitea.yaml
+ - deployments/gitea-db.yaml
+ - services/gitea.yaml
+ - services/gitea-db.yaml
+ - ingress/ingress.yaml
diff --git a/gitea/namespace.yaml b/gitea/namespace.yaml
new file mode 100644
index 0000000..4d0f469
--- /dev/null
+++ b/gitea/namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: gitea
\ No newline at end of file
diff --git a/gitea/pvc/gitea-data.yaml b/gitea/pvc/gitea-data.yaml
new file mode 100644
index 0000000..fbc63e3
--- /dev/null
+++ b/gitea/pvc/gitea-data.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: gitea-data
+ namespace: gitea
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 5Gi
+ storageClassName: ceph-rbd
diff --git a/gitea/pvc/gitea-db.yaml b/gitea/pvc/gitea-db.yaml
new file mode 100644
index 0000000..c466035
--- /dev/null
+++ b/gitea/pvc/gitea-db.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: gitea-db
+ namespace: gitea
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 2Gi
+ storageClassName: ceph-rbd
diff --git a/gitea/readme.md b/gitea/readme.md
new file mode 100644
index 0000000..5146b02
--- /dev/null
+++ b/gitea/readme.md
@@ -0,0 +1,12 @@
+# Manifiestos para Gitea
+Este repositorio contiene los manifiestos necesarios para desplegar Gitea, un servidor Git ligero, en el namespace gitea.
+
+## Despliegue
+
+ kubectl apply -f namespace.yaml
+ kubectl apply -f pvc/gitea-data.yaml
+ kubectl apply -f pvc/gitea-db.yaml
+ kubectl apply -f deployments/gitea-db.yaml
+ kubectl apply -f services/gitea-db.yaml
+ kubectl apply -f deployments/gitea.yaml
+ kubectl apply -f services/gitea.yaml
\ No newline at end of file
diff --git a/gitea/services/gitea-db.yaml b/gitea/services/gitea-db.yaml
new file mode 100644
index 0000000..d486c98
--- /dev/null
+++ b/gitea/services/gitea-db.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: gitea-db
+ namespace: gitea
+spec:
+ type: ClusterIP
+ selector:
+ app: gitea-db
+ ports:
+ - port: 3306
diff --git a/gitea/services/gitea.yaml b/gitea/services/gitea.yaml
new file mode 100644
index 0000000..e5c111d
--- /dev/null
+++ b/gitea/services/gitea.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: gitea
+ namespace: gitea
+spec:
+ type: NodePort
+ selector:
+ app: gitea
+ ports:
+ - name: http
+ port: 3000
+ targetPort: 3000
+ nodePort: 30300
diff --git a/harbor/values.yaml b/harbor/values.yaml
new file mode 100644
index 0000000..cd35e2e
--- /dev/null
+++ b/harbor/values.yaml
@@ -0,0 +1,56 @@
+expose:
+ type: ingress
+ tls:
+ enabled: true
+ certSource: auto
+ ingress:
+ ingressClassName: nginx
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+ hosts:
+ core: harbor.c2et.net
+ notary: notary.harbor.c2et.net
+
+externalURL: https://harbor.c2et.net
+
+persistence:
+ enabled: true
+ resourcePolicy: "keep"
+ persistentVolumeClaim:
+ registry:
+ storageClass: "ceph-rbd"
+ accessMode: ReadWriteOnce
+ chartmuseum:
+ storageClass: "ceph-rbd"
+ accessMode: ReadWriteOnce
+ jobservice:
+ storageClass: "ceph-rbd"
+ accessMode: ReadWriteOnce
+ database:
+ storageClass: "ceph-rbd"
+ accessMode: ReadWriteOnce
+ redis:
+ storageClass: "ceph-rbd"
+ accessMode: ReadWriteOnce
+ trivy:
+ storageClass: "ceph-rbd"
+ accessMode: ReadWriteOnce
+
+harborAdminPassword: Pozuelo12345
+
+portal:
+ replicaCount: 1
+
+core:
+ replicaCount: 1
+
+registry:
+ replicaCount: 1
+
+database:
+ type: internal
+ internal:
+ password: "root123"
+
+redis:
+ type: internal
diff --git a/kubectl b/kubectl
new file mode 100644
index 0000000..e69de29
diff --git a/rook/cluster/ceph-cluster-inicial.yaml b/rook/cluster/ceph-cluster-inicial.yaml
index ad68c86..9616319 100644
--- a/rook/cluster/ceph-cluster-inicial.yaml
+++ b/rook/cluster/ceph-cluster-inicial.yaml
@@ -15,6 +15,8 @@ spec:
- "192.168.4.0/24"
cluster:
- "192.168.4.0/24"
+ mgr:
+ count: 2
mon:
count: 3
@@ -34,6 +36,16 @@ spec:
operator: In
values: ["site-a","site-b"]
+ mgr:
+ nodeAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 100
+ preference:
+ matchExpressions:
+ - key: kubernetes.io/hostname
+ operator: In
+ values: ["srvfkvm01","srvfkvm04"]
+
storage:
useAllNodes: false
useAllDevices: false