Compare commits
29 Commits
bda9a3be17
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| aa976406e4 | |||
| 11da827e52 | |||
| 23c556938b | |||
| 3bfbd99958 | |||
| 1d06b6bb37 | |||
| 612b808259 | |||
| 9991f318fc | |||
| acc0b0bb79 | |||
| 0bbc20ca14 | |||
| bb76fc67dc | |||
| 549fd4ca37 | |||
| 4c5b451308 | |||
| bf2e26a8bf | |||
| 01cbdf2a1d | |||
| 0fc9bbb2c0 | |||
|
|
a3500d6250 | ||
|
|
f2f8a5cf5a | ||
|
|
91737b6592 | ||
|
|
b836c7afce | ||
| 9291e46fe9 | |||
| 2331da8cf8 | |||
| 2eff32d251 | |||
| 55c23dda1d | |||
|
|
8f7eee7cc1 | ||
|
|
b6da6350ac | ||
|
|
d173a90b2e | ||
| 452b04aa5d | |||
| dad001ae56 | |||
| 4389c53a2c |
@@ -1,10 +0,0 @@
|
|||||||
kubeadm join 192.168.0.20:6443 --token rvz86n.c8rdb9ygtikrwnub --discovery-token-ca-cert-hash sha256:f925653dfb3d2b4697395a272e0b07cf4eb16b7ae5a2cc3b33aeab1f36fe7d13 --control-plane --certificate-key eeab98651b2f07f6ce53649b2cca1bf3c449d4fe6270ec0645219cd8c6795ca7 --apiserver-advertise-address=192.168.4.2
|
|
||||||
|
|
||||||
|
|
||||||
sudo rm -rf /var/lib/kubelet/
|
|
||||||
sudo rm -rf /etc/kubernetes
|
|
||||||
sudo rm -rf /etc/cni/
|
|
||||||
sudo rm -rf /var/lib/etcd
|
|
||||||
sudo systemctl stop kubelet
|
|
||||||
sudo systemctl status kubelet
|
|
||||||
sudo kubeadm join 192.168.0.20:6443 --token rvz86n.c8rdb9ygtikrwnub --discovery-token-ca-cert-hash sha256:f925653dfb3d2b4697395a272e0b07cf4eb16b7ae5a2cc3b33aeab1f36fe7d13 --control-plane --certificate-key eeab98651b2f07f6ce53649b2cca1bf3c449d4fe6270ec0645219cd8c6795ca7 --apiserver-advertise-address=192.168.4.2
|
|
||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: app6
|
app.kubernetes.io/component: app6
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: app6
|
- name: app6
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-app6:6.0
|
image: harbor.c2et.net/apolo/xrf-app6:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: tcp-app6
|
- name: tcp-app6
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: colossus
|
app.kubernetes.io/component: colossus
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: colossus
|
- name: colossus
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-webcolossus:6.0
|
image: harbor.c2et.net/apolo/xrf-webcolossus:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: consumer
|
app.kubernetes.io/component: consumer
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: consumer
|
- name: consumer
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-consumer:6.0
|
image: harbor.c2et.net/apolo/xrf-consumer:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: drone
|
app.kubernetes.io/component: drone
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: drone
|
- name: drone
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-drone:6.0
|
image: harbor.c2et.net/apolo/xrf-drone:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
# Si Drone necesita otras vars del backend, puedes añadir:
|
# Si Drone necesita otras vars del backend, puedes añadir:
|
||||||
# envFrom:
|
# envFrom:
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ spec:
|
|||||||
app.kubernetes.io/component: ejabberd
|
app.kubernetes.io/component: ejabberd
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
|
|
||||||
# >>> Asegura permisos/ownership en volúmenes
|
|
||||||
securityContext:
|
securityContext:
|
||||||
runAsUser: 9000
|
runAsUser: 9000
|
||||||
runAsGroup: 9000
|
runAsGroup: 9000
|
||||||
@@ -62,7 +60,7 @@ spec:
|
|||||||
|
|
||||||
containers:
|
containers:
|
||||||
- name: ejabberd
|
- name: ejabberd
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-ejabberd:6.0
|
image: harbor.c2et.net/apolo/xrf-ejabberd:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: kurento
|
app.kubernetes.io/component: kurento
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: kurento-media-server
|
- name: kurento-media-server
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-kurento-media-server:6.0
|
image: harbor.c2et.net/apolo/xrf-kurento-media-server:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: kurento-api
|
app.kubernetes.io/component: kurento-api
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: kurento-api
|
- name: kurento-api
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-kurento-api:6.0
|
image: harbor.c2et.net/apolo/xrf-kurento-api:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: media
|
app.kubernetes.io/component: media
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: mediamtx
|
- name: mediamtx
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-media-server:6.0
|
image: harbor.c2et.net/apolo/xrf-media-server:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: nakama
|
app.kubernetes.io/component: nakama
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: nakama
|
- name: nakama
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-nakama:6.0
|
image: harbor.c2et.net/apolo/xrf-nakama:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: php
|
app.kubernetes.io/component: php
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: php-fpm
|
- name: php-fpm
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-php:6.0
|
image: harbor.c2et.net/apolo/xrf-php:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: php-fpm
|
- name: php-fpm
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ spec:
|
|||||||
app.kubernetes.io/component: portal
|
app.kubernetes.io/component: portal
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
# Contenedor de la app (como venías)
|
# Contenedor de la app (como venías)
|
||||||
- name: portal
|
- name: portal
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-portal-https:6.0
|
image: harbor.c2et.net/apolo/xrf-portal-https:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: app
|
- name: app
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ spec:
|
|||||||
app.kubernetes.io/component: postgres
|
app.kubernetes.io/component: postgres
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
securityContext:
|
securityContext:
|
||||||
fsGroup: 999
|
fsGroup: 999
|
||||||
initContainers:
|
initContainers:
|
||||||
@@ -40,7 +40,7 @@ spec:
|
|||||||
runAsUser: 0
|
runAsUser: 0
|
||||||
containers:
|
containers:
|
||||||
- name: postgres
|
- name: postgres
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-db:6.0
|
image: harbor.c2et.net/apolo/xrf-db:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
securityContext:
|
securityContext:
|
||||||
runAsUser: 999
|
runAsUser: 999
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: rabbitmq
|
app.kubernetes.io/component: rabbitmq
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: rabbitmq
|
- name: rabbitmq
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-rabbitmq:6.0
|
image: harbor.c2et.net/apolo/xrf-rabbitmq:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: streamer
|
app.kubernetes.io/component: streamer
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: streamer
|
- name: streamer
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-streamer-server:6.0
|
image: harbor.c2et.net/apolo/xrf-streamer-server:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command: ["npm","start"]
|
command: ["npm","start"]
|
||||||
envFrom:
|
envFrom:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: web
|
app.kubernetes.io/component: web
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: nginx
|
- name: nginx
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-web:6.0
|
image: harbor.c2et.net/apolo/xrf-web:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ spec:
|
|||||||
app.kubernetes.io/component: websocket
|
app.kubernetes.io/component: websocket
|
||||||
spec:
|
spec:
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: harbor-cred
|
- name: harbor-cred-apolo
|
||||||
containers:
|
containers:
|
||||||
- name: websocket
|
- name: websocket
|
||||||
image: harbor.c2et.com/xrf-ssl/xrf-websocket:6.0
|
image: harbor.c2et.net/apolo/xrf-websocket:6.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: ws
|
- name: ws
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ resources:
|
|||||||
- certs/certificate-meeting.yaml
|
- certs/certificate-meeting.yaml
|
||||||
|
|
||||||
# ConfigMaps
|
# ConfigMaps
|
||||||
- configmaps/configmap-coredns.yaml
|
|
||||||
- configmaps/configmap-ejabberd-inetrc.yaml
|
- configmaps/configmap-ejabberd-inetrc.yaml
|
||||||
- configmaps/configmap-ejabberd.yaml
|
- configmaps/configmap-ejabberd.yaml
|
||||||
- configmaps/configmap-kms-api.yaml
|
- configmaps/configmap-kms-api.yaml
|
||||||
@@ -49,7 +48,6 @@ resources:
|
|||||||
- deployments/deploy-app6.yaml
|
- deployments/deploy-app6.yaml
|
||||||
- deployments/deploy-colossus.yaml
|
- deployments/deploy-colossus.yaml
|
||||||
- deployments/deploy-consumer.yaml
|
- deployments/deploy-consumer.yaml
|
||||||
- deployments/deploy-coredns.yaml
|
|
||||||
- deployments/deploy-drone.yaml
|
- deployments/deploy-drone.yaml
|
||||||
- deployments/deploy-ejabberd.yaml
|
- deployments/deploy-ejabberd.yaml
|
||||||
- deployments/deploy-kms.yaml
|
- deployments/deploy-kms.yaml
|
||||||
@@ -68,7 +66,6 @@ resources:
|
|||||||
- services/svc-aliases-compose.yaml
|
- services/svc-aliases-compose.yaml
|
||||||
- services/svc-app6.yaml
|
- services/svc-app6.yaml
|
||||||
- services/svc-colossus.yaml
|
- services/svc-colossus.yaml
|
||||||
- services/svc-coredns.yaml
|
|
||||||
- services/svc-ejabberd.yaml
|
- services/svc-ejabberd.yaml
|
||||||
- services/svc-kms.yaml
|
- services/svc-kms.yaml
|
||||||
- services/svc-kurento-api.yaml
|
- services/svc-kurento-api.yaml
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IuYzJldC5jb20iOnsidXNlcm5hbWUiOiJ4YXZvciIsInBhc3N3b3JkIjoiTUBuYWJvMjAyNSIsImVtYWlsIjoibm8tcmVwbHlAYzJldC5jb20iLCJhdXRoIjoiZUdGMmIzSTZUVUJ1WVdKdk1qQXlOUT09In19fQ==
|
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IuYzJldC5uZXQiOnsidXNlcm5hbWUiOiJ4YXZvciIsInBhc3N3b3JkIjoiTUBuYWJvMjAyNSIsImVtYWlsIjoieGF2b3JAaG90bWFpbC5lcyIsImF1dGgiOiJlR0YyYjNJNlRVQnVZV0p2TWpBeU5RPT0ifX19
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: harbor-cred
|
name: harbor-cred
|
||||||
namespace: apolo
|
namespace: guacamole
|
||||||
type: kubernetes.io/dockerconfigjson
|
type: kubernetes.io/dockerconfigjson
|
||||||
|
|||||||
9
apolo/secrets/secret-harbor-cred.yaml.old
Normal file
9
apolo/secrets/secret-harbor-cred.yaml.old
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IuYzJldC5jb20iOnsidXNlcm5hbWUiOiJ4YXZvciIsInBhc3N3b3JkIjoiTUBuYWJvMjAyNSIsImVtYWlsIjoibm8tcmVwbHlAYzJldC5jb20iLCJhdXRoIjoiZUdGMmIzSTZUVUJ1WVdKdk1qQXlOUT09In19fQ==
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: harbor-cred
|
||||||
|
namespace: apolo
|
||||||
|
type: kubernetes.io/dockerconfigjson
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
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 """
|
|
||||||
<!doctype html><meta charset="utf-8"><title>ARGOS Panel</title>
|
|
||||||
<style>body{font-family:system-ui;margin:1.5rem} .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}
|
|
||||||
.card{border:1px solid #ddd;border-radius:10px;padding:10px} img{width:100%;height:160px;object-fit:cover;border-radius:8px}
|
|
||||||
button{padding:.4rem .6rem;margin-right:.3rem}</style>
|
|
||||||
<h1>ARGOS – Alarmas</h1>
|
|
||||||
<div class="grid" id="grid"></div>
|
|
||||||
<div style="margin-top:1rem"><video id="player" width="960" controls></video></div>
|
|
||||||
<script>
|
|
||||||
const fmt=t=>new Date(t*1000).toLocaleString();
|
|
||||||
async function load(){
|
|
||||||
const r=await fetch('/api/events?limit=100'); const data=await r.json();
|
|
||||||
const g=document.getElementById('grid'); g.innerHTML='';
|
|
||||||
for(const ev of data){
|
|
||||||
const d=document.createElement('div'); d.className='card';
|
|
||||||
const img = ev.thumb ? `<img src="${ev.thumb.replace('s3://','/api/url/THUMB?key=')}" alt="thumb">` : '';
|
|
||||||
d.innerHTML = `${img}<div><b>${ev.camera}</b> — ${fmt(ev.ts)}<br>${ev.label||''}</div>
|
|
||||||
<div style="margin-top:.4rem">
|
|
||||||
<button data-id="${ev.id}" data-action="clip">Ver clip</button>
|
|
||||||
<button data-path="${ev.camera}" data-action="live">En directo</button>
|
|
||||||
</div>`;
|
|
||||||
g.appendChild(d);
|
|
||||||
}
|
|
||||||
g.onclick=async (e)=>{
|
|
||||||
if(e.target.tagName!=='BUTTON') return;
|
|
||||||
const v=document.getElementById('player');
|
|
||||||
if(e.target.dataset.action==='clip'){
|
|
||||||
const id=e.target.dataset.id;
|
|
||||||
const j=await (await fetch('/api/url/'+id)).json();
|
|
||||||
v.src=j.url; v.play();
|
|
||||||
}else if(e.target.dataset.action==='live'){
|
|
||||||
const path=e.target.dataset.path;
|
|
||||||
// usa MediaMTX web player
|
|
||||||
window.open('http://mediamtx.argos.interna/?path='+encodeURIComponent(path),'_blank');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
load(); setInterval(load,10000);
|
|
||||||
</script>
|
|
||||||
"""
|
|
||||||
@@ -13,7 +13,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: mosquitto
|
- name: mosquitto
|
||||||
image: eclipse-mosquitto:2
|
image: eclipse-mosquitto:latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 1883
|
- containerPort: 1883
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: panel
|
- name: panel
|
||||||
image: python:3.13.7-slim-bookworm
|
image: harbor.c2et.net/library/python:3.13.7-slim-bookworm
|
||||||
command: ["/bin/sh","-c"]
|
command: ["/bin/sh","-c"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
|
|||||||
0
argos/kubectl
Normal file
0
argos/kubectl
Normal file
@@ -86,7 +86,7 @@ Este paso parte de una instalación limpia de openSUSE/SLES actualizada y con pe
|
|||||||
```bash
|
```bash
|
||||||
sudo zypper refresh
|
sudo zypper refresh
|
||||||
sudo zypper update
|
sudo zypper update
|
||||||
sudo zypper install -y curl ca-certificates keepalived chrony
|
sudo zypper install -y curl ca-certificates keepalived chrony yq jq open-iscsi yast2-iscsi-client multipath-tools gdisk util-linux helm tree git htop
|
||||||
```
|
```
|
||||||
|
|
||||||
### b) Añade el repositorio oficial de Kubernetes
|
### b) Añade el repositorio oficial de Kubernetes
|
||||||
|
|||||||
@@ -33,9 +33,37 @@ data:
|
|||||||
192.168.0.100 admin.powervault1.c2et.net
|
192.168.0.100 admin.powervault1.c2et.net
|
||||||
192.168.0.100 admin.powervault2.c2et.net
|
192.168.0.100 admin.powervault2.c2et.net
|
||||||
192.168.0.100 ceph.c2et.net
|
192.168.0.100 ceph.c2et.net
|
||||||
|
192.168.0.100 heimdall.c2et.net
|
||||||
|
|
||||||
|
# === dotcom ) ===
|
||||||
|
192.168.0.100 cockpit.c2et.com
|
||||||
|
192.168.0.100 git.c2et.com
|
||||||
|
192.168.0.100 harbor.c2et.com
|
||||||
|
192.168.0.100 wireguard.c2et.com
|
||||||
|
192.168.0.100 proxy.c2et.com
|
||||||
|
192.168.0.80 backend.apolo.c2et.com
|
||||||
|
192.168.0.80 portal.apolo.c2et.com
|
||||||
|
192.168.0.80 colossus.apolo.c2et.com
|
||||||
|
192.168.0.80 chat.apolo.c2et.com
|
||||||
|
192.168.0.80 muc.chat.apolo.c2et.com
|
||||||
|
192.168.0.81 streaming.apolo.c2et.com
|
||||||
|
192.168.0.81 meeting.apolo.c2et.com
|
||||||
|
|
||||||
|
# === dotnet ) ===
|
||||||
|
192.168.0.100 repo.c2et.net
|
||||||
|
192.168.0.100 git.c2et.net
|
||||||
|
192.168.0.100 wireguard.c2et.net
|
||||||
|
192.168.0.100 ceph.c2et.net
|
||||||
|
192.168.0.100 harbor.c2et.net
|
||||||
|
192.168.0.100 grafana.c2et.net
|
||||||
|
192.168.0.100 kubevirt.c2et.net
|
||||||
|
192.168.0.100 heimdall.c2et.net
|
||||||
|
192.168.0.100 argos.panel.c2et.net
|
||||||
|
192.168.0.100 vscode.c2et.net
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
}
|
}
|
||||||
forward . /etc/resolv.conf
|
forward . 8.8.8.8 1.1.1.1
|
||||||
cache 120
|
cache 120
|
||||||
# prometheus 0.0.0.0:9153 # <- activa si quieres métricas
|
# prometheus 0.0.0.0:9153 # <- activa si quieres métricas
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ resources:
|
|||||||
- configmap-coredns.yaml
|
- configmap-coredns.yaml
|
||||||
- deploy-coredns.yaml
|
- deploy-coredns.yaml
|
||||||
- svc-coredns.yaml
|
- svc-coredns.yaml
|
||||||
|
- svc-coredns-admin.yaml
|
||||||
|
|||||||
19
coredns/svc-coredns-admin.yaml
Normal file
19
coredns/svc-coredns-admin.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: coredns-custom-admin
|
||||||
|
namespace: coredns
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
loadBalancerIP: 192.168.0.110
|
||||||
|
selector:
|
||||||
|
app: coredns-custom
|
||||||
|
ports:
|
||||||
|
- name: dns-udp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: TCP
|
||||||
18
dynu-updater/cronjob.yaml
Normal file
18
dynu-updater/cronjob.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: dynu-updater
|
||||||
|
namespace: dynu-updater
|
||||||
|
spec:
|
||||||
|
schedule: "*/5 * * * *"
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: harbor-regcred
|
||||||
|
containers:
|
||||||
|
- name: dynu-updater
|
||||||
|
image: harbor.c2et.net/c3s/dynu-updater-c3s:1.0
|
||||||
|
imagePullPolicy: Always
|
||||||
|
restartPolicy: OnFailure
|
||||||
9
dynu-updater/harbor-regcred.yaml
Normal file
9
dynu-updater/harbor-regcred.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IuYzJldC5uZXQiOnsidXNlcm5hbWUiOiJ4YXZvciIsInBhc3N3b3JkIjoiTUBuYWJvMjAyNSIsImVtYWlsIjoiYWRtaW5AYzJldC5uZXQiLCJhdXRoIjoiZUdGMmIzSTZUVUJ1WVdKdk1qQXlOUT09In19fQ==
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: harbor-regcred
|
||||||
|
namespace: dynu-updater
|
||||||
|
type: kubernetes.io/dockerconfigjson
|
||||||
4
dynu-updater/kustomization.yaml
Normal file
4
dynu-updater/kustomization.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
resources:
|
||||||
|
- harbor-regcred.yaml
|
||||||
|
- namespace.yaml
|
||||||
|
- cronjob.yaml
|
||||||
4
dynu-updater/namespace.yaml
Normal file
4
dynu-updater/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: dynu-updater
|
||||||
119
dynu-updater/readme.md
Normal file
119
dynu-updater/readme.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# Dynu IP Updater en Kubernetes
|
||||||
|
|
||||||
|
Este proyecto despliega un cliente de Dynu personalizado como `CronJob` y `Job` en un clúster K3s/Kubernetes. Su función es mantener actualizada la dirección IP pública de un grupo de dominios gestionados en Dynu usando su API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Características
|
||||||
|
|
||||||
|
* Imagen Docker ligera basada en Alpine.
|
||||||
|
* Actualiza la IP pública mediante peticiones HTTP a la API de Dynu.
|
||||||
|
* Guarda la IP anterior para evitar actualizaciones innecesarias.
|
||||||
|
* Ejecutado periódicamente mediante `CronJob` (cada 5 minutos).
|
||||||
|
* Puede ejecutarse manualmente mediante un `Job`.
|
||||||
|
* Los logs de ejecución se almacenan y pueden consultarse con `kubectl logs`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚜 Estructura de archivos
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
k8s-dynu-updater/
|
||||||
|
├── cronjob.yaml # CronJob de Kubernetes
|
||||||
|
├── job-manual.yaml # Job manual para pruebas
|
||||||
|
├── kustomization.yaml # Kustomize para despliegue
|
||||||
|
├── namespace.yaml # Namespace aislado para el updater
|
||||||
|
```
|
||||||
|
|
||||||
|
La imagen Docker utilizada se crea con el script `update.sh` incrustado, que:
|
||||||
|
|
||||||
|
1. Detecta la IP pública actual.
|
||||||
|
2. Comprueba si ha cambiado desde la última ejecución.
|
||||||
|
3. Llama a la API de Dynu con usuario, grupo y contraseña hash MD5.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📂 Despliegue
|
||||||
|
|
||||||
|
1. Aplicar los manifiestos:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd k8s-dynu-updater
|
||||||
|
kubectl apply -k .
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Comprobar el estado:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n dynu-updater
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Ejecución manual
|
||||||
|
|
||||||
|
Para probar el script sin esperar al cron:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f job-manual.yaml
|
||||||
|
kubectl logs -n dynu-updater job/dynu-updater-manual
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚖️ Configuración del script
|
||||||
|
|
||||||
|
El script embebido en la imagen Docker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
USERNAME="xavor"
|
||||||
|
PASSWORD="M@nabo2025"
|
||||||
|
GROUP="Trabajo"
|
||||||
|
```
|
||||||
|
|
||||||
|
> La contraseña se convierte a hash MD5 antes de enviarla.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Seguridad
|
||||||
|
|
||||||
|
* La contraseña se envía como hash MD5.
|
||||||
|
* Se recomienda usar un "IP Update Password" diferente del de cuenta.
|
||||||
|
* Puedes montar `Secret` en Kubernetes para no incluir credenciales directamente en la imagen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Logs en Dynu
|
||||||
|
|
||||||
|
Dynu registra las actualizaciones entrantes. Puedes ver líneas como:
|
||||||
|
|
||||||
|
```
|
||||||
|
/nic/update?username=xavor&group=manabovalencia&myip=62.15.155.254&myipv6=no&password=***** Good
|
||||||
|
```
|
||||||
|
|
||||||
|
Esto confirma que el pod ha funcionado correctamente.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Referencias
|
||||||
|
|
||||||
|
* Dynu IP Update Protocol: [https://www.dynu.com/DynamicDNS/IP-Update-Protocol](https://www.dynu.com/DynamicDNS/IP-Update-Protocol)
|
||||||
|
* API: `https://api.dynu.com/nic/update`
|
||||||
|
* Cliente basado en `curl` y `cron` en Alpine Linux
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Mantenimiento
|
||||||
|
|
||||||
|
* Se puede adaptar a otros grupos (por ejemplo: `ManaboTorrevieja`).
|
||||||
|
* Si se quiere logs persistentes, se puede montar un volumen.
|
||||||
|
* Si se quiere gestionar con ArgoCD, agregarlo como `Application`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📄 Autor
|
||||||
|
|
||||||
|
Xavor (2025)
|
||||||
|
|
||||||
|
Este cliente se ha probado en K3s y Dynu, actualizando correctamente el grupo `ManaboValencia`.
|
||||||
57
external/configmaps/configmap.yaml
vendored
57
external/configmaps/configmap.yaml
vendored
@@ -4,6 +4,20 @@ metadata:
|
|||||||
name: nginx-router-config
|
name: nginx-router-config
|
||||||
namespace: external
|
namespace: external
|
||||||
data:
|
data:
|
||||||
|
_common.conf: |
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_read_timeout 3600;
|
||||||
|
proxy_send_timeout 3600;
|
||||||
|
client_max_body_size 0;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_ssl_server_name on;
|
||||||
|
|
||||||
router.conf: |
|
router.conf: |
|
||||||
server {
|
server {
|
||||||
listen 80 default_server;
|
listen 80 default_server;
|
||||||
@@ -33,3 +47,46 @@ data:
|
|||||||
proxy_ssl_verify off;
|
proxy_ssl_verify off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gitdotcom.conf: |
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name git.c2et.com;
|
||||||
|
location / {
|
||||||
|
include /etc/nginx/conf.d/_common.conf;
|
||||||
|
proxy_pass http://192.168.0.40:3001;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wireguarddotcom.conf: |
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name wireguard.c2et.com;
|
||||||
|
location / {
|
||||||
|
include /etc/nginx/conf.d/_common.conf;
|
||||||
|
proxy_pass http://192.168.0.40:51821;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
harbordotcom.conf: |
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name harbor.c2et.com;
|
||||||
|
location / {
|
||||||
|
include /etc/nginx/conf.d/_common.conf;
|
||||||
|
proxy_pass http://192.168.0.40:85;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cockpitdotcom.conf: |
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name cockpit.c2et.com;
|
||||||
|
location / {
|
||||||
|
proxy_pass https://192.168.0.40:9090;
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
37
external/configmaps/configmap.yaml.save
vendored
Normal file
37
external/configmaps/configmap.yaml.save
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: nginx-router-config
|
||||||
|
namespace: external
|
||||||
|
data:
|
||||||
|
router.conf: |
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
server_name admin.firewall.c2et.net;
|
||||||
|
location / {
|
||||||
|
proxy_pass https://192.168.0.1;
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
powervault1.conf: |
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name admin.powervault1.c2et.net;
|
||||||
|
location / {
|
||||||
|
proxy_pass https://192.168.0.71;
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
powervault2.conf: |
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name admin.powervault2.c2et.net;
|
||||||
|
location / {
|
||||||
|
proxy_pass https://192.168.0.74;
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
27
external/ingress/cockpitdotcom.yaml
vendored
Normal file
27
external/ingress/cockpitdotcom.yaml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: cockpitdotcom-ingress
|
||||||
|
namespace: external
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- cockpit.c2et.com
|
||||||
|
secretName: cockpitdotcom-tls
|
||||||
|
rules:
|
||||||
|
- host: cockpit.c2et.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: external-router-svc
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
27
external/ingress/gitdotcom.yaml
vendored
Normal file
27
external/ingress/gitdotcom.yaml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: gitdotcom-ingress
|
||||||
|
namespace: external
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- git.c2et.com
|
||||||
|
secretName: gitdotcom-tls
|
||||||
|
rules:
|
||||||
|
- host: git.c2et.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: external-router-svc
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
27
external/ingress/harbordotcom.yaml
vendored
Normal file
27
external/ingress/harbordotcom.yaml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: harbordotcom-ingress
|
||||||
|
namespace: external
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- harbor.c2et.com
|
||||||
|
secretName: harbordotcom-tls
|
||||||
|
rules:
|
||||||
|
- host: harbor.c2et.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: external-router-svc
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
28
external/ingress/wireguarddotcom.yaml
vendored
Normal file
28
external/ingress/wireguarddotcom.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: wireguarddotcom-ingress
|
||||||
|
namespace: external
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/upstream-vhost: "wireguard.c2et.com"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- wireguard.c2et.com
|
||||||
|
secretName: wireguarddotcom-tls
|
||||||
|
rules:
|
||||||
|
- host: wireguard.c2et.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: external-router-svc
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
@@ -15,7 +15,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: mysql
|
- name: mysql
|
||||||
image: mysql:8
|
image: mysql:latest
|
||||||
env:
|
env:
|
||||||
- name: MYSQL_ROOT_PASSWORD
|
- name: MYSQL_ROOT_PASSWORD
|
||||||
value: gitea123
|
value: gitea123
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ spec:
|
|||||||
- name: GITEA__database__USER
|
- name: GITEA__database__USER
|
||||||
value: "gitea"
|
value: "gitea"
|
||||||
- name: GITEA__database__PASSWD
|
- name: GITEA__database__PASSWD
|
||||||
value: "gitea123"
|
value: "gitea"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: gitea-data
|
- name: gitea-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
resources:
|
resources:
|
||||||
- namespace.yaml
|
- namespace.yaml
|
||||||
- pvc/gitea-data.yaml
|
|
||||||
- pvc/gitea-db.yaml
|
|
||||||
- deployments/gitea.yaml
|
- deployments/gitea.yaml
|
||||||
- deployments/gitea-db.yaml
|
- deployments/gitea-db.yaml
|
||||||
- services/gitea.yaml
|
- services/gitea.yaml
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ metadata:
|
|||||||
name: gitea
|
name: gitea
|
||||||
namespace: gitea
|
namespace: gitea
|
||||||
spec:
|
spec:
|
||||||
type: NodePort
|
|
||||||
selector:
|
selector:
|
||||||
app: gitea
|
app: gitea
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: 3000
|
port: 3000
|
||||||
targetPort: 3000
|
targetPort: 3000
|
||||||
nodePort: 30300
|
|
||||||
|
|||||||
28
grafana/kps-values.yaml
Normal file
28
grafana/kps-values.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
grafana:
|
||||||
|
enabled: true
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: nginx # <- tu IngressClass
|
||||||
|
hosts:
|
||||||
|
- grafana.c2et.net
|
||||||
|
tls:
|
||||||
|
- secretName: grafana-tls
|
||||||
|
hosts:
|
||||||
|
- grafana.c2et.net
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod # o el que uses
|
||||||
|
adminPassword: "Pozuelo12345" # vacío = autogenera; o pon tu contraseña si quieres
|
||||||
|
# puedes forzar la password así:
|
||||||
|
# admin:
|
||||||
|
# existingSecret: grafana-admin
|
||||||
|
# userKey: admin-user
|
||||||
|
# passwordKey: admin-password
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
ingress:
|
||||||
|
enabled: false # <- mantenlo interno (recomendado)
|
||||||
|
alertmanager:
|
||||||
|
ingress:
|
||||||
|
enabled: false # <- interno
|
||||||
@@ -29,6 +29,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: mysql-storage
|
- name: mysql-storage
|
||||||
mountPath: /var/lib/mysql
|
mountPath: /var/lib/mysql
|
||||||
|
subPath: data
|
||||||
volumes:
|
volumes:
|
||||||
- name: mysql-storage
|
- name: mysql-storage
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
|
|||||||
27
harbor/readme.md
Normal file
27
harbor/readme.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
## Instalacion de Harbor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Fase 1: Despliegue con Ingress
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm repo add harbor https://helm.goharbor.io
|
||||||
|
helm repo update
|
||||||
|
helm install harbor harbor/harbor \
|
||||||
|
--namespace harbor --create-namespace \
|
||||||
|
-f values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
> Una vez listo, podrás acceder a:
|
||||||
|
>
|
||||||
|
> **[https://harbor.c2et.net](https://harbor.c2et.net)**
|
||||||
|
>
|
||||||
|
> Usuario: `admin`
|
||||||
|
> Contraseña: la definida en `harborAdminPassword` (p.ej. `Harbor12345`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker login harbor.c2et.net
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ expose:
|
|||||||
enabled: true
|
enabled: true
|
||||||
certSource: auto
|
certSource: auto
|
||||||
ingress:
|
ingress:
|
||||||
ingressClassName: nginx
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
hosts:
|
hosts:
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ resources:
|
|||||||
- configmap/configmap.yaml
|
- configmap/configmap.yaml
|
||||||
- deployments/deployment.yaml
|
- deployments/deployment.yaml
|
||||||
- services/service.yaml
|
- services/service.yaml
|
||||||
|
- services/service-srv.yaml
|
||||||
- ingressclass/ingressclass.yaml
|
- ingressclass/ingressclass.yaml
|
||||||
|
|||||||
14
kubevirt/certs/kubevirt-certs.yaml
Normal file
14
kubevirt/certs/kubevirt-certs.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: kubevirt.io/v1
|
||||||
|
kind: KubeVirt
|
||||||
|
metadata:
|
||||||
|
name: kubevirt
|
||||||
|
namespace: kubevirt
|
||||||
|
spec:
|
||||||
|
certificateRotateStrategy:
|
||||||
|
selfSigned:
|
||||||
|
ca:
|
||||||
|
duration: "26280h" # 3 años
|
||||||
|
renewBefore: "720h" # 30 días antes
|
||||||
|
server:
|
||||||
|
duration: "8760h" # 1 año
|
||||||
|
renewBefore: "240h" # 10 días antes
|
||||||
@@ -13,6 +13,17 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
app: iso-server
|
app: iso-server
|
||||||
spec:
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: init-dirs
|
||||||
|
image: alpine:latest
|
||||||
|
command: ["sh","-lc"]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
mkdir -p /share/isos
|
||||||
|
chmod 755 /share/isos
|
||||||
|
volumeMounts:
|
||||||
|
- name: iso-storage
|
||||||
|
mountPath: /share
|
||||||
containers:
|
containers:
|
||||||
- name: httpd
|
- name: httpd
|
||||||
image: httpd:2.4
|
image: httpd:2.4
|
||||||
@@ -21,6 +32,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: iso-storage
|
- name: iso-storage
|
||||||
mountPath: /usr/local/apache2/htdocs
|
mountPath: /usr/local/apache2/htdocs
|
||||||
|
subPath: isos
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /
|
path: /
|
||||||
@@ -36,7 +48,7 @@ spec:
|
|||||||
|
|
||||||
- name: samba
|
- name: samba
|
||||||
image: dperson/samba
|
image: dperson/samba
|
||||||
args: ["-p", "-s", "isos;/share;yes;no"]
|
args: ["-p", "-s", "isos;/share/isos;yes;no"]
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 445
|
- containerPort: 445
|
||||||
securityContext:
|
securityContext:
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
# MinIO en Kubernetes — c2et.net (Site A/B)
|
|
||||||
|
|
||||||
Este paquete contiene manifiestos sin Helm para desplegar **dos instancias independientes de MinIO**,
|
|
||||||
una por site, usando tus StorageClasses `sc-me5-site-a` y `sc-me5-site-b`, y forzando programación por zona.
|
|
||||||
|
|
||||||
## Estructura
|
|
||||||
|
|
||||||
```
|
|
||||||
minio-k8s-c2et-net/
|
|
||||||
site-a/
|
|
||||||
namespace.yaml
|
|
||||||
secret-root.yaml
|
|
||||||
pvc.yaml
|
|
||||||
statefulset.yaml
|
|
||||||
service.yaml
|
|
||||||
ingress-api.yaml
|
|
||||||
ingress-console.yaml
|
|
||||||
site-b/
|
|
||||||
(idéntico con valores del site B)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Credenciales de administración
|
|
||||||
- Usuario: **admin**
|
|
||||||
- Password: **Pozuelo12345**
|
|
||||||
|
|
||||||
> Cambia estas credenciales en `secret-root.yaml` antes de ir a producción.
|
|
||||||
|
|
||||||
## Dominios
|
|
||||||
- Site A API: `s3-a.c2et.net`
|
|
||||||
- Site A Consola: `console.s3-a.c2et.net`
|
|
||||||
- Site B API: `s3-b.c2et.net`
|
|
||||||
- Site B Consola: `console.s3-b.c2et.net`
|
|
||||||
|
|
||||||
Requisitos previos:
|
|
||||||
- IngressClass `nginx` operativo.
|
|
||||||
- `cert-manager` con `ClusterIssuer` llamado `letsencrypt-prod`.
|
|
||||||
- DNS apuntando los hosts anteriores al Ingress Controller.
|
|
||||||
|
|
||||||
## Despliegue rápido
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f site-a/namespace.yaml
|
|
||||||
kubectl apply -f site-a/secret-root.yaml
|
|
||||||
kubectl apply -f site-a/pvc.yaml
|
|
||||||
kubectl apply -f site-a/service.yaml
|
|
||||||
kubectl apply -f site-a/statefulset.yaml
|
|
||||||
kubectl apply -f site-a/ingress-api.yaml
|
|
||||||
kubectl apply -f site-a/ingress-console.yaml
|
|
||||||
|
|
||||||
kubectl apply -f site-b/namespace.yaml
|
|
||||||
kubectl apply -f site-b/secret-root.yaml
|
|
||||||
kubectl apply -f site-b/pvc.yaml
|
|
||||||
kubectl apply -f site-b/service.yaml
|
|
||||||
kubectl apply -f site-b/statefulset.yaml
|
|
||||||
kubectl apply -f site-b/ingress-api.yaml
|
|
||||||
kubectl apply -f site-b/ingress-console.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Probar
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export AWS_ACCESS_KEY_ID=admin
|
|
||||||
export AWS_SECRET_ACCESS_KEY='Pozuelo12345'
|
|
||||||
export AWS_S3_FORCE_PATH_STYLE=true
|
|
||||||
|
|
||||||
aws --endpoint-url https://s3-a.c2et.net s3 mb s3://mi-bucket-a
|
|
||||||
aws --endpoint-url https://s3-a.c2et.net s3 ls
|
|
||||||
|
|
||||||
aws --endpoint-url https://s3-b.c2et.net s3 mb s3://mi-bucket-b
|
|
||||||
aws --endpoint-url https://s3-b.c2et.net s3 ls
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notas
|
|
||||||
|
|
||||||
- Los PVC usan `WaitForFirstConsumer` a través de tus StorageClasses; el `nodeSelector` del StatefulSet garantiza
|
|
||||||
que cada volumen se cree en el **site** correcto.
|
|
||||||
- Imagen MinIO: `quay.io/minio/minio:RELEASE.2025-02-20T00-00-00Z` (ajústala a la que certifiques).
|
|
||||||
- Tamaño del PVC por defecto: `2Ti` (modifícalo a tu necesidad).
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: minio
|
|
||||||
namespace: minio-site-a
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
app: minio
|
|
||||||
ports:
|
|
||||||
- name: api
|
|
||||||
port: 9000
|
|
||||||
targetPort: 9000
|
|
||||||
protocol: TCP
|
|
||||||
- name: console
|
|
||||||
port: 9001
|
|
||||||
targetPort: 9001
|
|
||||||
protocol: TCP
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: minio
|
|
||||||
namespace: minio-site-b
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
app: minio
|
|
||||||
ports:
|
|
||||||
- name: api
|
|
||||||
port: 9000
|
|
||||||
targetPort: 9000
|
|
||||||
protocol: TCP
|
|
||||||
- name: console
|
|
||||||
port: 9001
|
|
||||||
targetPort: 9001
|
|
||||||
protocol: TCP
|
|
||||||
33
readme.md
33
readme.md
@@ -114,6 +114,13 @@ Este repositorio contiene los **manifiestos, scripts y documentación** para des
|
|||||||
* Montado sobre dos **almacenes S3** (Minio), uno por **SITE**
|
* Montado sobre dos **almacenes S3** (Minio), uno por **SITE**
|
||||||
* Cada almacen en una cabina de almacenamiento **(DriverCSI)**
|
* Cada almacen en una cabina de almacenamiento **(DriverCSI)**
|
||||||
|
|
||||||
|
### 5.4. Repositorio interno
|
||||||
|
|
||||||
|
* **Repo**
|
||||||
|
* De momento, los repos de OpenSUSE 15.6 (ampliable)
|
||||||
|
* Servidor HTTP/HTTPS para centralizar las descargas
|
||||||
|
* servidor Samba para replicas a traves de diodo de datos
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. 📚 Índice de documentos y referencias cruzadas
|
## 6. 📚 Índice de documentos y referencias cruzadas
|
||||||
@@ -131,6 +138,7 @@ Este repositorio contiene los **manifiestos, scripts y documentación** para des
|
|||||||
| `comprobaciones.md` | Checklist tras cada paso crítico | [Ver](./comprobaciones.md) |
|
| `comprobaciones.md` | Checklist tras cada paso crítico | [Ver](./comprobaciones.md) |
|
||||||
| `script_limpieza.md` | Script para limpiar un nodo | [Ver](script_limpieza.md) |
|
| `script_limpieza.md` | Script para limpiar un nodo | [Ver](script_limpieza.md) |
|
||||||
| `coredns-demo\readme.md` | Ejemplo de Multus con CoreDNS | [Ver](./coredns-demo/readme.md) |
|
| `coredns-demo\readme.md` | Ejemplo de Multus con CoreDNS | [Ver](./coredns-demo/readme.md) |
|
||||||
|
| `harbor\readme.md` | Manual de instalacion de Harbor | [Ver](./harbor/readme.md) |
|
||||||
| `storage\readme.md` | Ejemplo de StorageClass | [Ver](./storage/readme.md) |
|
| `storage\readme.md` | Ejemplo de StorageClass | [Ver](./storage/readme.md) |
|
||||||
| `dashboard\readme.md` | Ejemplo con ingress dashboard | [Ver](./dashboard/readme.md) |
|
| `dashboard\readme.md` | Ejemplo con ingress dashboard | [Ver](./dashboard/readme.md) |
|
||||||
| `wireguard\readme.md` | Manual de WireGuard | [Ver](./wireguard/readme.md) |
|
| `wireguard\readme.md` | Manual de WireGuard | [Ver](./wireguard/readme.md) |
|
||||||
@@ -143,8 +151,9 @@ Este repositorio contiene los **manifiestos, scripts y documentación** para des
|
|||||||
| `mapas\readme.md` | Manual de instalación de Tileserver-GL | [Ver](./mapas/readme.md) |
|
| `mapas\readme.md` | Manual de instalación de Tileserver-GL | [Ver](./mapas/readme.md) |
|
||||||
| `argos\readme.md` | Manual de instalación de Argos Core | [Ver](./argos/readme.md) |
|
| `argos\readme.md` | Manual de instalación de Argos Core | [Ver](./argos/readme.md) |
|
||||||
| `multusk3s.md` | Notas para Multus en K3s | [Ver](./multusk3s.md) |
|
| `multusk3s.md` | Notas para Multus en K3s | [Ver](./multusk3s.md) |
|
||||||
| `minio\readme.md` | Manual de instalación de Minio para Velero | [Ver](./minio/readme.md) |
|
|
||||||
| `velero\readme.md` | Manual de instalación de Velero | [Ver](./velero/readme.md) |
|
| `velero\readme.md` | Manual de instalación de Velero | [Ver](./velero/readme.md) |
|
||||||
|
| `dynu-updater\readme.md` | Manual de Dynu-updater | [Ver](./dynu-updater/readme.md) |
|
||||||
|
| `repo\readme.md` | Manual del repo SUSE | [Ver](./repo/readme.md) |
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 📊 Estado actual de la instalación
|
## 7. 📊 Estado actual de la instalación
|
||||||
@@ -157,18 +166,20 @@ Este repositorio contiene los **manifiestos, scripts y documentación** para des
|
|||||||
| `Volumenes persistentes` | ✅ Completado | Rook Ceph a 4 nodos, falta ampliar a 5 nodos | [https://ceph.c2et.net](https://ceph.c2et.net/) | admin / Pozuelo12345 |
|
| `Volumenes persistentes` | ✅ Completado | Rook Ceph a 4 nodos, falta ampliar a 5 nodos | [https://ceph.c2et.net](https://ceph.c2et.net/) | admin / Pozuelo12345 |
|
||||||
| `Volumenes persistentes` | ✅ Completado | Driver para las cabinas de almacenamiendo DEEL Powervault | | |
|
| `Volumenes persistentes` | ✅ Completado | Driver para las cabinas de almacenamiendo DEEL Powervault | | |
|
||||||
| `Maquinas Virtuales` | ✅ Completado | Desplegado kubevirt, dashboard e isoserver | [https://kubevirt.c2et.net](https://kubevirt.c2et.net/) <br>[https://isoserver.c2et.net](https://isoserver.c2et.net/) | - |
|
| `Maquinas Virtuales` | ✅ Completado | Desplegado kubevirt, dashboard e isoserver | [https://kubevirt.c2et.net](https://kubevirt.c2et.net/) <br>[https://isoserver.c2et.net](https://isoserver.c2et.net/) | - |
|
||||||
| `Wireguard` | ✅ Completado | Funcionando | [https://wireguard.c2et.net](https://wireguard.c2et.net/) | Pozuelo12345 |
|
| `Wireguard` | ✅ Completado | version con acceso a 0.0 y a 200.0 | [https://wireguard.c2et.net](https://wireguard.c2et.net/) | Pozuelo12345 |
|
||||||
| `CoreDNS` | ✅ Completado | Funcionando | | |
|
| `CoreDNS` | ✅ Completado | Split DNS interno configurado en los host fisicos | | |
|
||||||
| `Apolo` | ✅ Completado | Funcionando | [https://portal.apolo.c2et.net](https://portal.apolo.c2et.net/) | admin / 123456 |
|
| `Apolo` | ✅ Completado | Funcionando, falta probar streaming | [https://portal.apolo.c2et.net](https://portal.apolo.c2et.net/) | admin / 123456 |
|
||||||
| `Gitea` | ✅ Completado | Funcionando | [https://git.c2et.net](https://git.c2et.net) | |
|
| `Gitea` | ✅ Completado | Funcionando | [https://git.c2et.net](https://git.c2et.net) | |
|
||||||
| `Harbor` | ✅ Completado | Funcionando | [https://harbor.c2et.net](https://harbor.c2et.net) | |
|
| `Harbor` | ✅ Completado | Funcionando pero no esta Ismael (solo estoy yo)| [https://harbor.c2et.net](https://harbor.c2et.net) | |
|
||||||
| `Guacamole` | ✅ Completado | Funcionando | [https://heimdall.c2et.net](https://heimdall.c2et.net) | |
|
| `Guacamole` | ✅ Completado | Funcionando, pero esta en blanco (hay que crear los hosts) | [https://heimdall.c2et.net](https://heimdall.c2et.net) | guacadmin / guacadmin |
|
||||||
| `VSCode` | ✅ Completado | Funcionando | [https://vscode.c2et.net](https://vscode.c2et.net) | Pozuelo12345 |
|
| `VSCode` | ✅ Completado | Funcionando | [https://vscode.c2et.net](https://vscode.c2et.net) | Pozuelo12345 |
|
||||||
| `Tileserver-GL` | ✅ Completado | Funcionando | [https://mapas.c2et.net](https://mapas.c2et.net) | |
|
| `Tileserver-GL` | ✅ Completado | Funcionando con mapa de España de prueba | [https://mapas.c2et.net](https://mapas.c2et.net) | |
|
||||||
| `External` | ✅ Completado | Funcionando | [https://admin.firewall.c2et.net](https://admin.firewall.c2et.net) <br>[https://admin.powervault1.c2et.net](https://admin.powervault1.c2et.net)<br> [https://admin.powervault2.c2et.net](https://admin.powervault2.c2et.net) | |
|
| `External` | ✅ Completado | Funcionando los servicios de docker | [https://admin.firewall.c2et.net](https://admin.firewall.c2et.net) <br>[https://admin.powervault1.c2et.net](https://admin.powervault1.c2et.net)<br> [https://admin.powervault2.c2et.net](https://admin.powervault2.c2et.net) | |
|
||||||
| `Argos Core` | ✅ Completado | Funcionando | [https://argos.panel.c2et.net/](https://argos.panel.c2et.net) | |
|
| `Argos Core` | ✅ Completado | Funcionando sin clientes configurados | [https://argos.panel.c2et.net/](https://argos.panel.c2et.net) | |
|
||||||
| `Minio` | ✅ Completado | Funcionando | [https://console.s3-a.c2et.net](https://console.s3-a.c2et.net) <br>[https://console.s3-b.c2et.net](https://console.s3-b.c2et.net) | admin / Pozuelo12345 |
|
| `Velero` | ✅ Completado | Copia de seguridad diaria de dynu y semanal de todo | | |
|
||||||
| `Velero` | ✅ Completado | Funcionando | | |
|
| `Dynu-updater` | ✅ Completado | Funcionando, actualiza el grupo "Trabajo" | | |
|
||||||
|
| `Repo` | ✅ Completado | Probando a ver si funciona | [http://repo.c2et.net/](https://repo.c2et.net) | |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
100
repo/configmap/repo-sources.yaml
Normal file
100
repo/configmap/repo-sources.yaml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: repo-sources
|
||||||
|
namespace: repo
|
||||||
|
data:
|
||||||
|
# Lista de orígenes a espejar
|
||||||
|
# Formato por línea: NAME|URL|SUBDIR
|
||||||
|
# SUBDIR cuelga de /mirror/repos (asegúrate de que tu Deployment monta el PVC en /usr/local/apache2/htdocs con subPath repos)
|
||||||
|
sources.txt: |
|
||||||
|
# openSUSE Leap 15.6 (básicos + updates)
|
||||||
|
repo-oss|http://download.opensuse.org/distribution/leap/15.6/repo/oss/|opensuse/leap/15.6/oss
|
||||||
|
repo-non-oss|http://download.opensuse.org/distribution/leap/15.6/repo/non-oss/|opensuse/leap/15.6/non-oss
|
||||||
|
update-oss|http://download.opensuse.org/update/leap/15.6/oss/|opensuse/leap/15.6/update/oss
|
||||||
|
update-non-oss|http://download.opensuse.org/update/leap/15.6/non-oss/|opensuse/leap/15.6/update/non-oss
|
||||||
|
update-sle|http://download.opensuse.org/update/leap/15.6/sle/|opensuse/leap/15.6/update/sle
|
||||||
|
backports|http://download.opensuse.org/update/leap/15.6/backports/|opensuse/leap/15.6/update/backports
|
||||||
|
|
||||||
|
# Codecs openh264
|
||||||
|
openh264|http://codecs.opensuse.org/openh264/openSUSE_Leap/|opensuse/openh264
|
||||||
|
|
||||||
|
# Terceros (opcional)
|
||||||
|
nvidia|https://download.nvidia.com/opensuse/leap/15.6/|thirdparty/nvidia/leap/15.6
|
||||||
|
k8s-stable|https://pkgs.k8s.io/core:/stable:/v1.33/rpm/|thirdparty/kubernetes/core/stable/v1.33/rpm
|
||||||
|
|
||||||
|
# Claves públicas a publicar en /mirror/keys
|
||||||
|
# Formato por línea: NAME|URL|FILENAME
|
||||||
|
# Ajusta las URLs si prefieres otras fuentes/ubicaciones oficiales
|
||||||
|
keys.txt: |
|
||||||
|
opensuse|https://download.opensuse.org/repositories/openSUSE:/Leap:/15.6:/Update/standard/repodata/repomd.xml.key|RPM-GPG-KEY-openSUSE
|
||||||
|
nvidia|https://download.nvidia.com/opensuse/repodata/repomd.xml.key|RPM-GPG-KEY-NVIDIA
|
||||||
|
k8s|https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key|RPM-GPG-KEY-k8s
|
||||||
|
|
||||||
|
# Script de sincronización diario (CronJob)
|
||||||
|
# - Sincroniza repos a /mirror/repos/...
|
||||||
|
# - Publica claves GPG en /mirror/keys
|
||||||
|
sync.sh: |
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SRC_LIST="/config/sources.txt"
|
||||||
|
KEYS_LIST="/config/keys.txt"
|
||||||
|
|
||||||
|
DEST_ROOT="/mirror/repos"
|
||||||
|
DEST_KEYS="/mirror/keys"
|
||||||
|
|
||||||
|
mkdir -p "$DEST_ROOT" "$DEST_KEYS"
|
||||||
|
|
||||||
|
# Requisitos
|
||||||
|
command -v wget >/dev/null 2>&1 || { echo "ERROR: wget requerido"; exit 1; }
|
||||||
|
if ! command -v rsync >/dev/null 2>&1; then
|
||||||
|
echo "Aviso: rsync no disponible; usaré wget para HTTP/HTTPS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "===== SYNC REPOS ====="
|
||||||
|
while IFS='|' read -r NAME URL SUBDIR; do
|
||||||
|
[[ -z "${NAME:-}" || "${NAME:0:1}" == "#" ]] && continue
|
||||||
|
|
||||||
|
DEST="${DEST_ROOT}/${SUBDIR}"
|
||||||
|
mkdir -p "$DEST"
|
||||||
|
|
||||||
|
echo "==> Sync ${NAME} (${URL}) -> ${DEST}"
|
||||||
|
|
||||||
|
if [[ "$URL" == rsync://* ]]; then
|
||||||
|
# Sincronización eficiente por rsync (si el mirror lo soporta)
|
||||||
|
rsync -aH --delete --partial --info=stats1,progress2 "${URL}" "${DEST}/"
|
||||||
|
else
|
||||||
|
# Mirror vía HTTP/HTTPS con wget
|
||||||
|
TMP="${DEST}.tmp"
|
||||||
|
mkdir -p "$TMP"
|
||||||
|
|
||||||
|
# -m (mirror), -np (no subir), -nH (sin host en ruta), robots=off
|
||||||
|
wget -m -np -nH -e robots=off -P "$TMP" --no-verbose --show-progress "$URL"
|
||||||
|
|
||||||
|
# Mover contenido espeljado a DEST (limpiando y dejando estructura limpia)
|
||||||
|
shopt -s dotglob nullglob
|
||||||
|
if compgen -G "$TMP/*" >/dev/null; then
|
||||||
|
rsync -a --delete "$TMP"/ "$DEST"/
|
||||||
|
fi
|
||||||
|
rm -rf "$TMP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Permisos legibles por httpd y Samba
|
||||||
|
chmod -R a+rX "$DEST"
|
||||||
|
done < "$SRC_LIST"
|
||||||
|
|
||||||
|
echo "===== SYNC KEYS ====="
|
||||||
|
if [[ -f "$KEYS_LIST" ]]; then
|
||||||
|
while IFS='|' read -r KNAME KURL KFILE; do
|
||||||
|
[[ -z "${KNAME:-}" || "${KNAME:0:1}" == "#" ]] && continue
|
||||||
|
echo "==> Key ${KNAME} (${KURL}) -> ${DEST_KEYS}/${KFILE}"
|
||||||
|
wget -q -O "${DEST_KEYS}/${KFILE}.tmp" "$KURL"
|
||||||
|
mv "${DEST_KEYS}/${KFILE}.tmp" "${DEST_KEYS}/${KFILE}"
|
||||||
|
chmod a+r "${DEST_KEYS}/${KFILE}"
|
||||||
|
done < "$KEYS_LIST"
|
||||||
|
else
|
||||||
|
echo "No hay KEYS_LIST ($KEYS_LIST), omitido."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "===== DONE ====="
|
||||||
144
repo/configure-local-repos.sh
Normal file
144
repo/configure-local-repos.sh
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ============================
|
||||||
|
# Configuración (ajusta aquí)
|
||||||
|
# ============================
|
||||||
|
BASE_URL="${BASE_URL:-http://repo.c2et.net}" # tu dominio del mirror (sin / al final)
|
||||||
|
LEAP_VER="${LEAP_VER:-15.6}" # versión de Leap
|
||||||
|
ENABLE_NVIDIA="${ENABLE_NVIDIA:-true}" # true/false
|
||||||
|
ENABLE_K8S="${ENABLE_K8S:-true}" # true/false
|
||||||
|
DISABLE_EXTERNAL="${DISABLE_EXTERNAL:-true}" # true/false (deshabilitar repos externos)
|
||||||
|
|
||||||
|
# Rutas base del mirror interno
|
||||||
|
REPO_BASE="${BASE_URL}/opensuse/leap/${LEAP_VER}"
|
||||||
|
KEYS_BASE="${BASE_URL}/keys"
|
||||||
|
|
||||||
|
# Directorio de repos dnf/zypp
|
||||||
|
REPOS_DIR="/etc/zypp/repos.d"
|
||||||
|
|
||||||
|
# ============================
|
||||||
|
# Helpers
|
||||||
|
# ============================
|
||||||
|
need_root() {
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "Este script debe ejecutarse como root (o con sudo)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
have_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
write_repo() {
|
||||||
|
local alias="$1" name="$2" baseurl="$3" gpgkey="$4"
|
||||||
|
local path="${REPOS_DIR}/${alias}.repo"
|
||||||
|
|
||||||
|
cat >"${path}.tmp" <<EOF
|
||||||
|
[${alias}]
|
||||||
|
name=${name}
|
||||||
|
enabled=1
|
||||||
|
autorefresh=1
|
||||||
|
baseurl=${baseurl}
|
||||||
|
type=rpm-md
|
||||||
|
gpgcheck=1
|
||||||
|
gpgkey=${gpgkey}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Solo mueve si cambió (idempotente)
|
||||||
|
if [[ ! -f "${path}" ]] || ! cmp -s "${path}.tmp" "${path}"; then
|
||||||
|
mv "${path}.tmp" "${path}"
|
||||||
|
echo " - Escrito ${path}"
|
||||||
|
else
|
||||||
|
rm -f "${path}.tmp"
|
||||||
|
echo " - Sin cambios ${path}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
import_key() {
|
||||||
|
local url="$1" file="key-$(basename "$url")"
|
||||||
|
# rpm ignora si ya está importada; esto es idempotente
|
||||||
|
echo " - Importando clave: $url"
|
||||||
|
rpm --import "$url" || {
|
||||||
|
echo " * Aviso: no se pudo importar $url. ¿Hay conectividad al mirror?" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_external_repos() {
|
||||||
|
echo "Deshabilitando repos externos conocidos..."
|
||||||
|
# Deshabilita TODO lo que no sea *_local que creemos, de forma segura:
|
||||||
|
# Busca todos los alias actuales y deshabilita los que no terminen en '-local'
|
||||||
|
local aliases
|
||||||
|
aliases=$(zypper --non-interactive lr -u | awk 'NR>2 {print $1,$2}' | tail -n +1 | awk '{print $2}')
|
||||||
|
for a in $aliases; do
|
||||||
|
if [[ "$a" != *-local ]]; then
|
||||||
|
# Algunos sistemas traen alias con espacios; saltamos los complicados
|
||||||
|
if [[ "$a" =~ ^[A-Za-z0-9._:-]+$ ]]; then
|
||||||
|
zypper --non-interactive mr -d "$a" || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================
|
||||||
|
# Main
|
||||||
|
# ============================
|
||||||
|
need_root
|
||||||
|
|
||||||
|
if ! have_cmd zypper; then
|
||||||
|
echo "No se encontró zypper. ¿Es openSUSE/SLE este sistema?" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "== Configurando repos locales desde ${BASE_URL} para Leap ${LEAP_VER} =="
|
||||||
|
|
||||||
|
mkdir -p "$REPOS_DIR"
|
||||||
|
|
||||||
|
# 1) Importa claves GPG desde tu mirror
|
||||||
|
echo "Importando claves GPG desde ${KEYS_BASE} ..."
|
||||||
|
import_key "${KEYS_BASE}/RPM-GPG-KEY-openSUSE" || true
|
||||||
|
$ENABLE_NVIDIA && import_key "${KEYS_BASE}/RPM-GPG-KEY-NVIDIA" || true
|
||||||
|
$ENABLE_K8S && import_key "${KEYS_BASE}/RPM-GPG-KEY-k8s" || true
|
||||||
|
|
||||||
|
# 2) Repos base de openSUSE
|
||||||
|
echo "Escribiendo archivos .repo para repos locales..."
|
||||||
|
write_repo "repo-oss-local" "repo-oss-local" "${REPO_BASE}/oss" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
write_repo "repo-non-oss-local" "repo-non-oss-local" "${REPO_BASE}/non-oss" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
write_repo "update-oss-local" "update-oss-local" "${REPO_BASE}/update/oss" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
write_repo "update-non-oss-local" "update-non-oss-local" "${REPO_BASE}/update/non-oss" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
write_repo "update-sle-local" "update-sle-local" "${REPO_BASE}/update/sle" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
write_repo "update-backports-local" "update-backports-local" "${REPO_BASE}/update/backports" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
write_repo "openh264-local" "openh264-local" "${BASE_URL}/opensuse/openh264" "${KEYS_BASE}/RPM-GPG-KEY-openSUSE"
|
||||||
|
|
||||||
|
# 3) Repos de terceros (opcional)
|
||||||
|
if $ENABLE_NVIDIA; then
|
||||||
|
write_repo "nvidia-local" "nvidia-local" \
|
||||||
|
"${BASE_URL}/thirdparty/nvidia/leap/${LEAP_VER}" \
|
||||||
|
"${KEYS_BASE}/RPM-GPG-KEY-NVIDIA"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $ENABLE_K8S; then
|
||||||
|
write_repo "k8s-stable-local" "k8s-stable-local" \
|
||||||
|
"${BASE_URL}/thirdparty/kubernetes/core/stable/v1.33/rpm" \
|
||||||
|
"${KEYS_BASE}/RPM-GPG-KEY-k8s"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) Deshabilitar repos externos si procede
|
||||||
|
if $DISABLE_EXTERNAL; then
|
||||||
|
disable_external_repos
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5) Refrescar repos (no interactivo)
|
||||||
|
echo "Refrescando repos..."
|
||||||
|
zypper --non-interactive --gpg-auto-import-keys ref || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== Listado final de repos =="
|
||||||
|
zypper lr -d || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Listo. Si quieres personalizar:"
|
||||||
|
echo " BASE_URL=... LEAP_VER=... ENABLE_NVIDIA=true/false ENABLE_K8S=true/false DISABLE_EXTERNAL=true/false \\"
|
||||||
|
echo " sudo -E ./$(basename "$0")"
|
||||||
38
repo/cronjobs/repo-sync.yaml
Normal file
38
repo/cronjobs/repo-sync.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: repo-sync
|
||||||
|
namespace: repo
|
||||||
|
spec:
|
||||||
|
schedule: "15 2 * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 2
|
||||||
|
failedJobsHistoryLimit: 2
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: sync
|
||||||
|
image: alpine:latest
|
||||||
|
command: ["sh","-lc"]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
apk add --no-cache rsync wget bash coreutils
|
||||||
|
chmod +x /config/sync.sh
|
||||||
|
/config/sync.sh
|
||||||
|
volumeMounts:
|
||||||
|
- name: repo-storage
|
||||||
|
mountPath: /mirror
|
||||||
|
- name: repo-config
|
||||||
|
mountPath: /config
|
||||||
|
volumes:
|
||||||
|
- name: repo-storage
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: repo-pvc
|
||||||
|
- name: repo-config
|
||||||
|
configMap:
|
||||||
|
name: repo-sources
|
||||||
|
defaultMode: 0755
|
||||||
59
repo/deployments/repo-server.yaml
Normal file
59
repo/deployments/repo-server.yaml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: repo-server
|
||||||
|
namespace: repo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: repo-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: repo-server
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: init-dirs
|
||||||
|
image: alpine:3.20
|
||||||
|
command: ["sh","-lc"]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
mkdir -p /share/repos
|
||||||
|
chmod 755 /share /share/repos
|
||||||
|
volumeMounts:
|
||||||
|
- name: repo-storage
|
||||||
|
mountPath: /share
|
||||||
|
containers:
|
||||||
|
- name: httpd
|
||||||
|
image: httpd:2.4
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
volumeMounts:
|
||||||
|
- name: repo-storage
|
||||||
|
mountPath: /usr/local/apache2/htdocs
|
||||||
|
subPath: repos
|
||||||
|
readinessProbe:
|
||||||
|
httpGet: { path: /, port: 80 }
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet: { path: /, port: 80 }
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
|
|
||||||
|
- name: samba
|
||||||
|
image: dperson/samba
|
||||||
|
args: ["-p", "-s", "repos;/share/repos;yes;no"]
|
||||||
|
ports:
|
||||||
|
- containerPort: 445
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 0
|
||||||
|
volumeMounts:
|
||||||
|
- name: repo-storage
|
||||||
|
mountPath: /share
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: repo-storage
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: repo-pvc
|
||||||
23
repo/ingress/ingress-repo.yaml
Normal file
23
repo/ingress/ingress-repo.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: repo
|
||||||
|
namespace: repo
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts: [ "repo.c2et.net" ]
|
||||||
|
secretName: repo-c2et-net-tls
|
||||||
|
rules:
|
||||||
|
- host: repo.c2et.net
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: repo-http
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
26
repo/kustomization.yaml
Normal file
26
repo/kustomization.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
namespace: repo
|
||||||
|
|
||||||
|
commonLabels:
|
||||||
|
app.kubernetes.io/name: repo-mirror
|
||||||
|
app.kubernetes.io/part-of: suse-repo
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- pvc.yaml
|
||||||
|
- configmap/repo-sources.yaml
|
||||||
|
- deployments/repo-server.yaml
|
||||||
|
- services/service-http.yaml
|
||||||
|
- services/service-samba.yaml
|
||||||
|
- ingress/ingress-repo.yaml
|
||||||
|
- cronjobs/repo-sync.yaml
|
||||||
|
|
||||||
|
images:
|
||||||
|
- name: httpd
|
||||||
|
newTag: "2.4"
|
||||||
|
- name: alpine
|
||||||
|
newTag: "latest"
|
||||||
|
- name: dperson/samba
|
||||||
|
newTag: "latest"
|
||||||
4
repo/namespace.yaml
Normal file
4
repo/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: repo
|
||||||
12
repo/pvc.yaml
Normal file
12
repo/pvc.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: repo-pvc
|
||||||
|
namespace: repo
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteMany
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Ti
|
||||||
|
storageClassName: sc-me5-site-a
|
||||||
71
repo/readme.md
Normal file
71
repo/readme.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Repositorio Privado openSUSE
|
||||||
|
|
||||||
|
Este despliegue en Kubernetes crea un **mirror interno de repositorios de openSUSE** (y de terceros opcionales, como NVIDIA o Kubernetes). Sirve para que los servidores de nuestra red se actualicen **desde dentro**, sin depender de internet.
|
||||||
|
|
||||||
|
El sistema funciona con:
|
||||||
|
|
||||||
|
* **Servidor HTTP/HTTPS** → los clientes SUSE acceden vía `http://repo.c2et.net/...` o `https://repo.c2et.net/...` para descargar paquetes y metadatos.
|
||||||
|
* **Servidor Samba (SMB)** → expone la misma carpeta por red. Esto nos permite que el **“diodo de datos”** copie los repos de manera unidireccional hacia la red clasificada. Así aseguramos que las máquinas en la red sensible reciben actualizaciones sin conectividad exterior.
|
||||||
|
|
||||||
|
La carpeta de repos se actualiza automáticamente cada día mediante un **CronJob**, que sincroniza contra los repos oficiales de openSUSE y de terceros.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cómo desplegarlo
|
||||||
|
|
||||||
|
1. Ajusta **dominio** en el Ingress y (si quieres) IP fija en el Service de Samba.
|
||||||
|
2. Revisa tamaño de **PVC** (mínimo 300 GB recomendado).
|
||||||
|
3. (Opcional) Cambia o amplía la lista en `sources.txt` (por ejemplo, usando mirrors con `rsync://`).
|
||||||
|
4. Despliega todo de una vez con **Kustomize**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -k repo/
|
||||||
|
```
|
||||||
|
|
||||||
|
*(Si prefieres, aún puedes aplicar los manifiestos uno por uno en el orden indicado en la carpeta `repo/`.)*
|
||||||
|
|
||||||
|
5. Para lanzar una sincronización inicial manual (sin esperar al cron):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl create job --from=cronjob/repo-sync repo-sync-now -n repo
|
||||||
|
kubectl logs -f job/repo-sync-now -n repo
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuración en los clientes SUSE
|
||||||
|
|
||||||
|
En los clientes no hace falta configurar repos manualmente. Basta con ejecutar el **script de cliente** incluido en este repo (`configure-local-repos.sh`). Este script:
|
||||||
|
|
||||||
|
* Importa las claves GPG desde `http://repo.c2et.net/keys/`.
|
||||||
|
* Crea los `.repo` apuntando al mirror interno.
|
||||||
|
* Deshabilita los repos externos para que solo se usen los `-local`.
|
||||||
|
|
||||||
|
### Uso del script en el cliente
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x configure-local-repos.sh
|
||||||
|
sudo ./configure-local-repos.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Esto deja el sistema listo para trabajar solo con los repos locales.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ventajas de esta arquitectura
|
||||||
|
|
||||||
|
* **Seguridad**: los clientes nunca salen a internet, solo acceden al repo interno.
|
||||||
|
* **Control**: el mirror se actualiza de forma programada (p. ej. de madrugada). Siempre sabemos qué versiones están disponibles.
|
||||||
|
* **Simplicidad**: los clientes usan HTTP/HTTPS estándar; el Ingress se encarga del TLS si hace falta.
|
||||||
|
* **Integración con el diodo**: gracias a Samba, la carpeta puede replicarse unidireccionalmente hacia la red clasificada.
|
||||||
|
* **Verificación**: zypper siempre valida las firmas GPG de los paquetes, aunque se distribuyan por HTTP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sugerencias y mejoras
|
||||||
|
|
||||||
|
* Usar **mirrors oficiales con rsync** para ahorrar ancho de banda y tiempo de sincronización.
|
||||||
|
* Añadir `--bwlimit` en el `sync.sh` si queremos limitar consumo nocturno de ancho de banda.
|
||||||
|
* Sustituir `httpd` por `nginx` si se busca mayor rendimiento en descargas masivas.
|
||||||
|
* Proteger el Ingress con autenticación si se expone fuera de la red de confianza.
|
||||||
|
* Mantener el **script de cliente** actualizado para simplificar el alta de repos en todos los servidores SUSE.
|
||||||
14
repo/services/service-http.yaml
Normal file
14
repo/services/service-http.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: repo-http
|
||||||
|
namespace: repo
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: repo-server
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
15
repo/services/service-samba.yaml
Normal file
15
repo/services/service-samba.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: repo-samba
|
||||||
|
namespace: repo
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
loadBalancerIP: 192.168.0.106
|
||||||
|
selector:
|
||||||
|
app: repo-server
|
||||||
|
ports:
|
||||||
|
- name: samba
|
||||||
|
port: 445
|
||||||
|
targetPort: 445
|
||||||
|
protocol: TCP
|
||||||
38
rook/borrar_discos.sh
Executable file
38
rook/borrar_discos.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# ⚠️ AJUSTA ESTA LISTA A TUS DISCOS DE CEPH (NUNCA el del sistema)
|
||||||
|
DISKS=(sdb sdc sdd sde sdf sdg)
|
||||||
|
|
||||||
|
echo "Discos objetivo:"
|
||||||
|
printf ' - /dev/%s\n' "${DISKS[@]}"
|
||||||
|
echo
|
||||||
|
read -r -p "¿Seguro que quieres LIMPIAR estos discos? Escribe 'SI' para continuar: " ok
|
||||||
|
[[ "$ok" == "SI" ]] || { echo "Cancelado."; exit 1; }
|
||||||
|
|
||||||
|
for d in "${DISKS[@]}"; do
|
||||||
|
dev="/dev/$d"
|
||||||
|
echo ">>> Limpiando $dev"
|
||||||
|
|
||||||
|
# 0) Opcional: si vienen de un cluster Ceph viejo, intenta zappearlos con ceph-volume
|
||||||
|
if command -v ceph-volume >/dev/null 2>&1; then
|
||||||
|
sudo ceph-volume lvm zap --destroy "$dev" || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1) GPT/MBR
|
||||||
|
sudo sgdisk --zap-all "$dev" || true
|
||||||
|
|
||||||
|
# 2) Firmas de FS/LVM/RAID
|
||||||
|
sudo wipefs -a "$dev" || true
|
||||||
|
|
||||||
|
# 3) TRIM (si soporta). Si falla, hacemos un “zero header” de 10 MiB.
|
||||||
|
if ! sudo blkdiscard -f "$dev"; then
|
||||||
|
sudo dd if=/dev/zero of="$dev" bs=1M count=10 oflag=direct conv=fsync || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) Limpieza de particiones fantasma en el kernel
|
||||||
|
sudo partprobe "$dev" || true
|
||||||
|
|
||||||
|
echo ">>> $dev limpiado."
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Hecho."
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
apiVersion: ceph.rook.io/v1
|
|
||||||
kind: CephCluster
|
|
||||||
metadata:
|
|
||||||
name: rook-ceph
|
|
||||||
namespace: rook-ceph
|
|
||||||
spec:
|
|
||||||
cephVersion:
|
|
||||||
image: quay.io/ceph/ceph:v19.2.3
|
|
||||||
dataDirHostPath: /var/lib/rook
|
|
||||||
|
|
||||||
network:
|
|
||||||
provider: host
|
|
||||||
addressRanges:
|
|
||||||
public:
|
|
||||||
- "192.168.4.0/24"
|
|
||||||
cluster:
|
|
||||||
- "192.168.4.0/24"
|
|
||||||
mgr:
|
|
||||||
count: 2
|
|
||||||
|
|
||||||
mon:
|
|
||||||
count: 3
|
|
||||||
allowMultiplePerNode: false
|
|
||||||
|
|
||||||
dashboard:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
# Evita OSDs en el futuro nodo árbitro (cuando lo añadas)
|
|
||||||
placement:
|
|
||||||
osd:
|
|
||||||
nodeAffinity:
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
nodeSelectorTerms:
|
|
||||||
- matchExpressions:
|
|
||||||
- key: topology.kubernetes.io/zone
|
|
||||||
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
|
|
||||||
nodes:
|
|
||||||
- name: srvfkvm01
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5bb177a1716
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5dc196bd3a7
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5f81b10f7ef
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d6151cca8afd
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d62f1e5e9699
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d64f204b2405
|
|
||||||
|
|
||||||
- name: srvfkvm02
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127eef88828273
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127f879197de32
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128081a076ba0c
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128114a93e33b9
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94300301281a7b1fc151a
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128235ba79d801
|
|
||||||
|
|
||||||
- name: srvfkvm03
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128aef3bb4e0ae
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b0e3d8bc1dc
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b2b3f446dd7
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b4440c2d027
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b5e42510c2a
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b7d442e592c
|
|
||||||
|
|
||||||
- name: srvfkvm04
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c003012887ebfca6752
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c0030128896e360075f
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288ac038600d4
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288c62acb6efc
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288e456c6d441
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288f976534b4f
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
apiVersion: ceph.rook.io/v1
|
|
||||||
kind: CephCluster
|
|
||||||
metadata:
|
|
||||||
name: rook-ceph
|
|
||||||
namespace: rook-ceph
|
|
||||||
spec:
|
|
||||||
cephVersion:
|
|
||||||
image: quay.io/ceph/ceph:v19.2.3
|
|
||||||
dataDirHostPath: /var/lib/rook
|
|
||||||
|
|
||||||
network:
|
|
||||||
provider: host
|
|
||||||
connections:
|
|
||||||
publicNetwork: "192.168.3.0/24"
|
|
||||||
clusterNetwork: "192.168.3.0/24"
|
|
||||||
|
|
||||||
mon:
|
|
||||||
count: 3
|
|
||||||
allowMultiplePerNode: false
|
|
||||||
|
|
||||||
dashboard:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
# Evita OSDs en el futuro nodo árbitro (cuando lo añadas)
|
|
||||||
placement:
|
|
||||||
osd:
|
|
||||||
nodeAffinity:
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
nodeSelectorTerms:
|
|
||||||
- matchExpressions:
|
|
||||||
- key: topology.kubernetes.io/zone
|
|
||||||
operator: In
|
|
||||||
values: ["site-a","site-b"]
|
|
||||||
|
|
||||||
storage:
|
|
||||||
useAllNodes: false
|
|
||||||
useAllDevices: false
|
|
||||||
nodes:
|
|
||||||
- name: srvfkvm01
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5bb177a1716
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5dc196bd3a7
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5f81b10f7ef
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d6151cca8afd
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d62f1e5e9699
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d64f204b2405
|
|
||||||
|
|
||||||
- name: srvfkvm02
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127eef88828273
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127f879197de32
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128081a076ba0c
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128114a93e33b9
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94300301281a7b1fc151a
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128235ba79d801
|
|
||||||
|
|
||||||
- name: srvfkvm03
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128aef3bb4e0ae
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b0e3d8bc1dc
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b2b3f446dd7
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b4440c2d027
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b5e42510c2a
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b7d442e592c
|
|
||||||
|
|
||||||
- name: srvfkvm04
|
|
||||||
devices:
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c003012887ebfca6752
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c0030128896e360075f
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288ac038600d4
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288c62acb6efc
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288e456c6d441
|
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288f976534b4f
|
|
||||||
109
rook/cluster/ceph-cluster.yaml
Normal file
109
rook/cluster/ceph-cluster.yaml
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
apiVersion: ceph.rook.io/v1
|
||||||
|
kind: CephCluster
|
||||||
|
metadata:
|
||||||
|
name: rook-ceph
|
||||||
|
namespace: rook-ceph
|
||||||
|
spec:
|
||||||
|
cephVersion:
|
||||||
|
image: quay.io/ceph/ceph:v18
|
||||||
|
dataDirHostPath: /var/lib/rook
|
||||||
|
|
||||||
|
dashboard:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
mon:
|
||||||
|
count: 3
|
||||||
|
allowMultiplePerNode: false
|
||||||
|
|
||||||
|
mgr:
|
||||||
|
count: 2
|
||||||
|
|
||||||
|
# Reglas de colocación: mons (A/B/arbiter), mgrs (A/B), OSDs solo en A/B
|
||||||
|
placement:
|
||||||
|
mon:
|
||||||
|
nodeAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: topology.kubernetes.io/zone
|
||||||
|
operator: In
|
||||||
|
values: ["site-a","site-b","arbiter"]
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- labelSelector:
|
||||||
|
matchLabels: { app: rook-ceph-mon }
|
||||||
|
maxSkew: 1
|
||||||
|
topologyKey: topology.kubernetes.io/zone
|
||||||
|
whenUnsatisfiable: DoNotSchedule
|
||||||
|
mgr:
|
||||||
|
nodeAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: topology.kubernetes.io/zone
|
||||||
|
operator: In
|
||||||
|
values: ["site-a","site-b"]
|
||||||
|
podAntiAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app
|
||||||
|
operator: In
|
||||||
|
values: ["rook-ceph-mgr"]
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- labelSelector:
|
||||||
|
matchLabels: { app: rook-ceph-mgr }
|
||||||
|
maxSkew: 1
|
||||||
|
topologyKey: topology.kubernetes.io/zone
|
||||||
|
whenUnsatisfiable: DoNotSchedule
|
||||||
|
osd:
|
||||||
|
nodeAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: topology.kubernetes.io/zone
|
||||||
|
operator: In
|
||||||
|
values: ["site-a","site-b"]
|
||||||
|
|
||||||
|
cleanupPolicy:
|
||||||
|
wipeDevicesFromOtherClusters: true
|
||||||
|
sanitizeDisks:
|
||||||
|
method: quick
|
||||||
|
dataSource: zero
|
||||||
|
|
||||||
|
storage:
|
||||||
|
useAllNodes: false
|
||||||
|
useAllDevices: false
|
||||||
|
nodes:
|
||||||
|
- name: srvfkvm01
|
||||||
|
devices:
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5bb177a1716, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5dc196bd3a7, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5f81b10f7ef, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d6151cca8afd, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d62f1e5e9699, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d64f204b2405, config: { deviceClass: ssd } }
|
||||||
|
- name: srvfkvm02
|
||||||
|
devices:
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127eef88828273, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127f879197de32, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128081a076ba0c, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128114a93e33b9, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94300301281a7b1fc151a, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128235ba79d801, config: { deviceClass: ssd } }
|
||||||
|
- name: srvfkvm03
|
||||||
|
devices:
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128aef3bb4e0ae, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b0e3d8bc1dc, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b2b3f446dd7, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b4440c2d027, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b5e42510c2a, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b7d442e592c, config: { deviceClass: ssd } }
|
||||||
|
- name: srvfkvm04
|
||||||
|
devices:
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c003012887ebfca6752, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c0030128896e360075f, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288ac038600d4, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288c62acb6efc, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288e456c6d441, config: { deviceClass: ssd } }
|
||||||
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288f976534b4f, config: { deviceClass: ssd } }
|
||||||
@@ -5,8 +5,8 @@ metadata:
|
|||||||
namespace: rook-ceph
|
namespace: rook-ceph
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.200.0/24,192.168.0.0/24,10.244.0.0/16,192.168.4.0/24"
|
# nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.200.0/24,192.168.0.0/24,10.244.0.0/16,192.168.4.0/24"
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
tls:
|
tls:
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
apiVersion: ceph.rook.io/v1
|
|
||||||
kind: CephBlockPool
|
|
||||||
metadata:
|
|
||||||
name: rbd-2x2-sites
|
|
||||||
namespace: rook-ceph
|
|
||||||
spec:
|
|
||||||
failureDomain: zone
|
|
||||||
replicated:
|
|
||||||
size: 4
|
|
||||||
18
rook/pools/ceph-blockpool-rbd.yaml
Normal file
18
rook/pools/ceph-blockpool-rbd.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: ceph.rook.io/v1
|
||||||
|
kind: CephBlockPool
|
||||||
|
metadata:
|
||||||
|
name: rbd-2x2-sites
|
||||||
|
namespace: rook-ceph
|
||||||
|
spec:
|
||||||
|
deviceClass: ssd
|
||||||
|
failureDomain: zone
|
||||||
|
replicated:
|
||||||
|
size: 4
|
||||||
|
replicasPerFailureDomain: 2
|
||||||
|
subFailureDomain: host
|
||||||
|
requireSafeReplicaSize: true
|
||||||
|
parameters:
|
||||||
|
pg_autoscale_mode: "on"
|
||||||
|
min_size: "2"
|
||||||
|
mirroring:
|
||||||
|
enabled: false
|
||||||
446
rook/readme.md
446
rook/readme.md
@@ -1,60 +1,26 @@
|
|||||||
# Despliegue de Rook‑Ceph en clúster **Kubernetes** (SUSE) con discos locales (Bluestore)
|
# Despliegue de **Rook‑Ceph** en Kubernetes (SUSE) con 2 zonas + **árbitro**
|
||||||
|
|
||||||
> Guía actualizada para un clúster **Kubernetes** (no K3s) en SUSE, con 4 nodos iniciales y **futura ampliación a stretch** con un quinto nodo **árbitro**. Discos locales (RAID/HBA), red de almacenamiento dedicada **VLAN 30 – 192.168.3.0/24**, y exposición del dashboard **vía Ingress NGINX** con TLS.
|
> Guía basada en el estado **actual** del clúster (A/B + *arbiter*), sin fase previa “sin árbitro”. Discos locales (Bluestore), distribución por **zona**, 3 MON (uno por zona) y 2 MGR (uno por site A y otro por site B). Pool RBD con **size=4** (2+2 por zona) y **min
|
||||||
|
> to**=2.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Requisitos previos
|
## 1) Topología y requisitos
|
||||||
|
|
||||||
* 4 nodos Kubernetes operativos: `srvfkvm01`, `srvfkvm02`, `srvfkvm03`, `srvfkvm04` (control-plane o mixtos)
|
* Nodos y zonas:
|
||||||
* Cada nodo con **6 discos** dedicados (\~894 GB) para Ceph
|
|
||||||
* Acceso a Internet desde los nodos
|
|
||||||
* Red de almacenamiento dedicada **VLAN 30 – 192.168.3.0/24** (Ceph public/cluster)
|
|
||||||
* `kubectl` configurado y permisos de admin
|
|
||||||
|
|
||||||
> **Nota de versiones**: ejemplos probados con Rook 1.17.x y Ceph v19.x (Squid) o v18.x (Reef). En los manifiestos se usa una imagen estable.
|
* **site-a**: `srvfkvm01`, `srvfkvm02`
|
||||||
|
* **site-b**: `srvfkvm03`, `srvfkvm04`
|
||||||
|
* **arbiter**: `srvfkvm05` *(sin OSDs)*
|
||||||
|
* Cada nodo de datos con **6 discos** dedicados a Ceph (usar rutas persistentes `/dev/disk/by-id/...`).
|
||||||
|
* Acceso a Internet desde los nodos. `kubectl` con permisos de admin.
|
||||||
|
* Versiones empleadas: **Rook v1.18.x**, **Ceph v18 (Reef)**.
|
||||||
|
|
||||||
|
> **Objetivo de resiliencia**: tolerar la caída completa de un site (A **o** B). El árbitro aloja MON (y opcionalmente MGR), **no** OSDs.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) Preparar discos en SUSE (solo discos de datos)
|
## 2) Etiquetar nodos por **zona**
|
||||||
|
|
||||||
Instala utilidades necesarias en **cada nodo**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo zypper -n install gdisk util-linux
|
|
||||||
```
|
|
||||||
|
|
||||||
Limpieza segura **solo** de `sdb…sdg` (ajusta si difiere):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
set -euo pipefail
|
|
||||||
DISKS=(sdb sdc sdd sde sdf sdg)
|
|
||||||
|
|
||||||
for d in "${DISKS[@]}"; do
|
|
||||||
echo ">>> /dev/$d"
|
|
||||||
sudo sgdisk --zap-all /dev/$d || true # limpia GPT/MBR
|
|
||||||
sudo wipefs -a /dev/$d || true # borra firmas FS/LVM
|
|
||||||
sudo blkdiscard -f /dev/$d || \ # TRIM (si soporta)
|
|
||||||
sudo dd if=/dev/zero of=/dev/$d bs=1M count=10 oflag=direct,dsync
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
Obtén las rutas **persistentes** *by‑id* para cada disco (en cada nodo):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
for d in sdb sdc sdd sde sdf sdg; do
|
|
||||||
echo "=== $HOSTNAME -> $d ==="
|
|
||||||
ls -l /dev/disk/by-id/ | awk -v d="$d" '$NF ~ ("/" d "$") {print "/dev/disk/by-id/"$9}'
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Usa siempre** `/dev/disk/by-id/...` en los manifiestos (campo `fullpath:`) para evitar cambios de letra.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3) Etiquetado de nodos por **site**
|
|
||||||
|
|
||||||
Vamos a distribuir por zonas lógicas desde el inicio (A/B). El árbitro llegará después.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# SITE A
|
# SITE A
|
||||||
@@ -64,35 +30,72 @@ kubectl label node srvfkvm02 topology.kubernetes.io/zone=site-a --overwrite
|
|||||||
# SITE B
|
# SITE B
|
||||||
kubectl label node srvfkvm03 topology.kubernetes.io/zone=site-b --overwrite
|
kubectl label node srvfkvm03 topology.kubernetes.io/zone=site-b --overwrite
|
||||||
kubectl label node srvfkvm04 topology.kubernetes.io/zone=site-b --overwrite
|
kubectl label node srvfkvm04 topology.kubernetes.io/zone=site-b --overwrite
|
||||||
```
|
|
||||||
|
|
||||||
> Cuando exista el nodo **árbitro**, se etiquetará como `topology.kubernetes.io/zone=arbiter`.
|
# ÁRBITRO
|
||||||
|
kubectl label node srvfkvm05 topology.kubernetes.io/zone=arbiter --overwrite
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4) Instalar Rook (CRDs, comunes y operador)
|
## 3) Preparar discos (SUSE)
|
||||||
|
|
||||||
|
Instalar utilidades (en **cada nodo de datos**):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo zypper -n install gdisk util-linux
|
||||||
|
```
|
||||||
|
|
||||||
|
Limpiar de forma segura (ajusta IDs según cada host):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ejemplo genérico; usa *by-id* reales de cada nodo
|
||||||
|
for d in \
|
||||||
|
/dev/disk/by-id/wwn-...a \
|
||||||
|
/dev/disk/by-id/wwn-...b \
|
||||||
|
/dev/disk/by-id/wwn-...c \
|
||||||
|
/dev/disk/by-id/wwn-...d \
|
||||||
|
/dev/disk/by-id/wwn-...e \
|
||||||
|
/dev/disk/by-id/wwn-...f; do
|
||||||
|
echo ">>> $d"
|
||||||
|
sudo wipefs -a "$d" || true
|
||||||
|
# Cabecera 100MiB
|
||||||
|
sudo dd if=/dev/zero of="$d" bs=1M count=100 oflag=direct,dsync || true
|
||||||
|
# Cola 100MiB
|
||||||
|
real=$(readlink -f "$d"); dev=$(basename "$real")
|
||||||
|
sz=$(cat /sys/class/block/$dev/size); tail=$((100*1024*1024/512)); seek=$((sz - tail)); ((seek<0)) && seek=0
|
||||||
|
sudo dd if=/dev/zero of="$real" bs=512 seek="$seek" count="$tail" oflag=direct,dsync || true
|
||||||
|
sudo partprobe "$real" || true; sudo udevadm settle || true
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Consejo**: guarda las rutas *by‑id* exactas de cada nodo; son las que se usarán en el `CephCluster`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4) Instalar Rook (CRDs + operador)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl create namespace rook-ceph || true
|
kubectl create namespace rook-ceph || true
|
||||||
|
|
||||||
# Clonar repo oficial (opcional para tener toolbox/ejemplos)
|
# CRDs + common + operator (Rook v1.18.x)
|
||||||
git clone https://github.com/rook/rook.git
|
kubectl apply -f https://raw.githubusercontent.com/rook/rook/v1.18.0/deploy/examples/crds.yaml \
|
||||||
cd rook/deploy/examples
|
-f https://raw.githubusercontent.com/rook/rook/v1.18.0/deploy/examples/common.yaml \
|
||||||
|
-f https://raw.githubusercontent.com/rook/rook/v1.18.0/deploy/examples/operator.yaml
|
||||||
|
|
||||||
kubectl apply -f crds.yaml -f common.yaml -f operator.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Comprueba el operador:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n rook-ceph get pods | grep operator
|
kubectl -n rook-ceph get pods | grep operator
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Toolbox** (útil para diagnosticar):
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> kubectl -n rook-ceph apply -f https://raw.githubusercontent.com/rook/rook/v1.18.0/deploy/examples/toolbox.yaml
|
||||||
|
> ```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) CephCluster – 4 nodos, discos *by‑id*, red de storage (VLAN 30)
|
## 5) Manifiesto **CephCluster** (A/B + árbitro, OSDs solo en A/B)
|
||||||
|
|
||||||
Archivo `cluster/ceph-cluster.yaml`:
|
Archivo `cluster/ceph-cluster.yaml` **adaptado a tu entorno actual**:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: ceph.rook.io/v1
|
apiVersion: ceph.rook.io/v1
|
||||||
@@ -102,72 +105,103 @@ metadata:
|
|||||||
namespace: rook-ceph
|
namespace: rook-ceph
|
||||||
spec:
|
spec:
|
||||||
cephVersion:
|
cephVersion:
|
||||||
image: quay.io/ceph/ceph:v19.2.3 # estable (puedes usar v18.2.x si prefieres)
|
image: quay.io/ceph/ceph:v18
|
||||||
dataDirHostPath: /var/lib/rook
|
dataDirHostPath: /var/lib/rook
|
||||||
|
|
||||||
# Red: usamos hostNetworking y restringimos a VLAN de storage
|
dashboard:
|
||||||
network:
|
enabled: true
|
||||||
provider: host
|
|
||||||
addressRanges:
|
mgr:
|
||||||
public:
|
count: 2
|
||||||
- "192.168.3.0/24"
|
|
||||||
cluster:
|
|
||||||
- "192.168.3.0/24"
|
|
||||||
|
|
||||||
mon:
|
mon:
|
||||||
count: 3
|
count: 3
|
||||||
allowMultiplePerNode: false
|
allowMultiplePerNode: false
|
||||||
|
|
||||||
dashboard:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
# No queremos OSDs en el futuro nodo árbitro
|
|
||||||
placement:
|
placement:
|
||||||
osd:
|
# MGR repartidos entre site-a y site-b
|
||||||
|
mgr:
|
||||||
nodeAffinity:
|
nodeAffinity:
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
nodeSelectorTerms:
|
nodeSelectorTerms:
|
||||||
- matchExpressions:
|
- matchExpressions:
|
||||||
- key: topology.kubernetes.io/zone
|
- key: topology.kubernetes.io/zone
|
||||||
operator: In
|
operator: In
|
||||||
values: ["site-a", "site-b"]
|
values: ["site-a","site-b"]
|
||||||
|
podAntiAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app
|
||||||
|
operator: In
|
||||||
|
values: ["rook-ceph-mgr"]
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: rook-ceph-mgr
|
||||||
|
maxSkew: 1
|
||||||
|
topologyKey: topology.kubernetes.io/zone
|
||||||
|
whenUnsatisfiable: DoNotSchedule
|
||||||
|
|
||||||
|
# MON uno por zona (site-a, site-b, arbiter)
|
||||||
|
mon:
|
||||||
|
nodeAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: topology.kubernetes.io/zone
|
||||||
|
operator: In
|
||||||
|
values: ["site-a","site-b","arbiter"]
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: rook-ceph-mon
|
||||||
|
maxSkew: 1
|
||||||
|
topologyKey: topology.kubernetes.io/zone
|
||||||
|
whenUnsatisfiable: DoNotSchedule
|
||||||
|
|
||||||
|
security:
|
||||||
|
cephx:
|
||||||
|
csi: {}
|
||||||
|
daemon: {}
|
||||||
|
rbdMirrorPeer: {}
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
useAllNodes: false
|
|
||||||
useAllDevices: false
|
useAllDevices: false
|
||||||
nodes:
|
nodes:
|
||||||
- name: srvfkvm01
|
- name: srvfkvm01
|
||||||
devices:
|
devices:
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5bb177a1716
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5bb177a1716, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5dc196bd3a7
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5dc196bd3a7, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5f81b10f7ef
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d5f81b10f7ef, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d6151cca8afd
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d6151cca8afd, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d62f1e5e9699
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d62f1e5e9699, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d64f204b2405
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94b003012d64f204b2405, config: {deviceClass: ssd}}
|
||||||
- name: srvfkvm02
|
- name: srvfkvm02
|
||||||
devices:
|
devices:
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127eef88828273
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127eef88828273, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127f879197de32
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030127f879197de32, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128081a076ba0c
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128081a076ba0c, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128114a93e33b9
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128114a93e33b9, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94300301281a7b1fc151a
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d94300301281a7b1fc151a, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128235ba79d801
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9430030128235ba79d801, config: {deviceClass: ssd}}
|
||||||
- name: srvfkvm03
|
- name: srvfkvm03
|
||||||
devices:
|
devices:
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128aef3bb4e0ae
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128aef3bb4e0ae, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b0e3d8bc1dc
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b0e3d8bc1dc, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b2b3f446dd7
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b2b3f446dd7, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b4440c2d027
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b4440c2d027, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b5e42510c2a
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b5e42510c2a, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b7d442e592c
|
- { fullpath: /dev/disk/by-id/wwn-0x64cd98f036d9510030128b7d442e592c, config: {deviceClass: ssd}}
|
||||||
- name: srvfkvm04
|
- name: srvfkvm04
|
||||||
devices:
|
devices:
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c003012887ebfca6752
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c003012887ebfca6752, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c0030128896e360075f
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c0030128896e360075f, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288ac038600d4
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288ac038600d4, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288c62acb6efc
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288c62acb6efc, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288e456c6d441
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288e456c6d441, config: {deviceClass: ssd}}
|
||||||
- fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288f976534b4f
|
- { fullpath: /dev/disk/by-id/wwn-0x6ec2a72037894c00301288f976534b4f, config: {deviceClass: ssd}}
|
||||||
```
|
```
|
||||||
|
|
||||||
Aplicar y verificar:
|
Aplicar y verificar:
|
||||||
@@ -177,13 +211,20 @@ kubectl apply -f cluster/ceph-cluster.yaml
|
|||||||
kubectl -n rook-ceph get pods
|
kubectl -n rook-ceph get pods
|
||||||
```
|
```
|
||||||
|
|
||||||
> Instala el **toolbox** para diagnósticos: `kubectl -n rook-ceph apply -f rook/deploy/examples/toolbox.yaml`
|
> **Nota**: los MON deberían quedar uno en `site-a`, otro en `site-b` y otro en `arbiter`; los MGR en `site-a` y `site-b`. Los OSDs solo en A/B.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Pool RBD inicial (replica **4** sobre **hosts**) + StorageClass
|
## 6) Activar **Orchestrator** (backend Rook)
|
||||||
|
|
||||||
> Con 2 sites (A/B) y **sin** árbitro, **no** uses `failureDomain: zone` con `size: 4` o las PGs quedarán *undersized*. Empezamos con **`host`** y, cuando activemos **stretch**, pasaremos a `zone`.
|
```bash
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph orch set backend rook
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph orch status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7) Pool **RBD** 2×2 por **zona** + StorageClass
|
||||||
|
|
||||||
`pools/ceph-blockpool-rbd.yaml`:
|
`pools/ceph-blockpool-rbd.yaml`:
|
||||||
|
|
||||||
@@ -194,9 +235,16 @@ metadata:
|
|||||||
name: rbd-2x2-sites
|
name: rbd-2x2-sites
|
||||||
namespace: rook-ceph
|
namespace: rook-ceph
|
||||||
spec:
|
spec:
|
||||||
failureDomain: host
|
deviceClass: ssd
|
||||||
|
failureDomain: zone
|
||||||
replicated:
|
replicated:
|
||||||
size: 4
|
size: 4 # 2 por site (A/B)
|
||||||
|
minSize: 2
|
||||||
|
replicasPerFailureDomain: 2
|
||||||
|
subFailureDomain: host
|
||||||
|
requireSafeReplicaSize: true
|
||||||
|
parameters:
|
||||||
|
pg_autoscale_mode: "on"
|
||||||
```
|
```
|
||||||
|
|
||||||
`storageclasses/rbd.yaml`:
|
`storageclasses/rbd.yaml`:
|
||||||
@@ -226,47 +274,25 @@ allowVolumeExpansion: true
|
|||||||
mountOptions: ["discard"]
|
mountOptions: ["discard"]
|
||||||
```
|
```
|
||||||
|
|
||||||
Aplicar:
|
Aplicar y comprobar:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f pools/ceph-blockpool-rbd.yaml
|
kubectl apply -f pools/ceph-blockpool-rbd.yaml
|
||||||
kubectl apply -f storageclasses/rbd.yaml
|
kubectl apply -f storageclasses/rbd.yaml
|
||||||
kubectl get sc
|
|
||||||
|
# Verificaciones rápidas
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph osd pool get rbd-2x2-sites size
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph osd pool get rbd-2x2-sites min_size
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph osd crush rule dump rbd-2x2-sites -f json-pretty
|
||||||
```
|
```
|
||||||
|
|
||||||
> Si creaste el pool inicialmente con `failureDomain: zone` y ves `active+undersized`, crea y asigna una **CRUSH rule** a host:
|
> La regla CRUSH generada elige **zona** y luego **host** (2 réplicas por zona). Con OSDs solo en A/B, el árbitro **no** aloja datos.
|
||||||
>
|
|
||||||
> ```bash
|
|
||||||
> kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash -lc '
|
|
||||||
> set -e
|
|
||||||
> ceph osd crush rule create-replicated rbd-4x-host default host || true
|
|
||||||
> ceph osd pool set rbd-2x2-sites crush_rule rbd-4x-host
|
|
||||||
> ceph osd pool get rbd-2x2-sites crush_rule
|
|
||||||
> '
|
|
||||||
> ```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Marcar OSDs como **SSD** (si Ceph los detecta como HDD por el HBA)
|
## 8) Dashboard por **Ingress** (opcional)
|
||||||
|
|
||||||
```bash
|
`ingress/dashboard.yaml` (backend HTTP:7000):
|
||||||
# Desde el toolbox
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash -lc '
|
|
||||||
for id in $(ceph osd ls); do ceph osd crush rm-device-class osd.$id || true; done
|
|
||||||
for id in $(ceph osd ls); do ceph osd crush set-device-class ssd osd.$id; done
|
|
||||||
ceph osd tree | egrep "zone|host|osd."
|
|
||||||
'
|
|
||||||
```
|
|
||||||
|
|
||||||
> Si más adelante creas un pool **solo‑SSD**, añade `spec.deviceClass: ssd` al `CephBlockPool`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8) Dashboard por **Ingress** (NGINX) en `ceph.c2et.net`
|
|
||||||
|
|
||||||
> El dashboard del MGR escucha por defecto en **HTTP 7000**. Hacemos **TLS en el Ingress** (cert‑manager) y **HTTP** hacia el backend.
|
|
||||||
|
|
||||||
`ingress/dashboard.yaml`:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
@@ -275,15 +301,11 @@ metadata:
|
|||||||
name: ceph-dashboard
|
name: ceph-dashboard
|
||||||
namespace: rook-ceph
|
namespace: rook-ceph
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
tls:
|
|
||||||
- hosts: ["ceph.c2et.net"]
|
|
||||||
secretName: ceph-dashboard-tls
|
|
||||||
rules:
|
rules:
|
||||||
- host: ceph.c2et.net
|
- host: ceph.example.local
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
@@ -295,27 +317,24 @@ spec:
|
|||||||
number: 7000
|
number: 7000
|
||||||
```
|
```
|
||||||
|
|
||||||
Credenciales:
|
Contraseña admin:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Usuario por defecto
|
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath='{.data.password}' | base64 -d; echo
|
||||||
admin
|
|
||||||
|
|
||||||
# Contraseña generada
|
|
||||||
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{.data.password}" | base64 -d; echo
|
|
||||||
|
|
||||||
# Cambiar contraseña (ejemplo)
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash -lc \
|
|
||||||
'echo -n "MiNuevaPass" | ceph dashboard ac-user-set-password admin -i -'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> Si prefieres **HTTPS 8443** también hacia el backend, habilita TLS en el dashboard de Ceph y cambia el Ingress a `backend-protocol: "HTTPS"` y puerto `8443` (y opcionalmente `proxy-ssl-verify: "off"`).
|
Crear usuario admin.c3s (el otro suele resetear la pass):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash -lc \
|
||||||
|
'echo -n "Pozuelo12345" | ceph dashboard ac-user-create admin.c3s administrator -i - && ceph dashboard ac-user-list'
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Prueba rápida de PVC
|
## 9) Prueba de StorageClass (PVC + Pod)
|
||||||
|
|
||||||
`tests/pvc-test.yaml`:
|
`tests/pvc.yaml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -330,7 +349,7 @@ spec:
|
|||||||
storageClassName: ceph-rbd
|
storageClassName: ceph-rbd
|
||||||
```
|
```
|
||||||
|
|
||||||
`tests/pod-test.yaml`:
|
`tests/pod.yaml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -351,97 +370,42 @@ spec:
|
|||||||
claimName: test-rbd
|
claimName: test-rbd
|
||||||
```
|
```
|
||||||
|
|
||||||
Aplicar y verificar:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f tests/pvc-test.yaml
|
kubectl apply -f tests/pvc.yaml
|
||||||
kubectl apply -f tests/pod-test.yaml
|
kubectl apply -f tests/pod.yaml
|
||||||
kubectl exec -it rbd-tester -- sh -c 'df -h /data && dd if=/dev/zero of=/data/test.bin bs=1M count=100 && ls -lh /data'
|
kubectl exec -it rbd-tester -- sh -c 'df -h /data && dd if=/dev/zero of=/data/test.bin bs=1M count=100 && ls -lh /data'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) **Ampliación futura**: modo **Stretch** con **árbitro** (2 sites + arbiter)
|
## 10) Guardar manifiestos exactos desde el clúster
|
||||||
|
|
||||||
Objetivo: supervivencia a la caída completa de un site y distribución **2+2** de réplicas entre `site-a` y `site-b`.
|
|
||||||
|
|
||||||
1. **Añade el nodo árbitro** y etiqueta:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl label node <NODO_ARBITRO> topology.kubernetes.io/zone=arbiter --overwrite
|
# CephCluster “limpio” sin campos efímeros
|
||||||
```
|
kubectl -n rook-ceph get cephcluster rook-ceph -o yaml --show-managed-fields=false \
|
||||||
|
| yq 'del(.metadata.creationTimestamp,.metadata.generation,.metadata.resourceVersion,.metadata.uid,.status)' \
|
||||||
|
> ceph-cluster-export.yaml
|
||||||
|
|
||||||
2. **Actualiza el CephCluster** a stretch (5 MON):
|
# Pool y StorageClass
|
||||||
|
kubectl -n rook-ceph get cephblockpool rbd-2x2-sites -o yaml > ceph-blockpool-export.yaml
|
||||||
```yaml
|
kubectl get sc ceph-rbd -o yaml > storageclass-rbd-export.yaml
|
||||||
# parche del CephCluster (fragmento spec)
|
|
||||||
mon:
|
|
||||||
count: 5
|
|
||||||
allowMultiplePerNode: false
|
|
||||||
stretchCluster:
|
|
||||||
failureDomainLabel: topology.kubernetes.io/zone
|
|
||||||
subFailureDomain: host
|
|
||||||
zones:
|
|
||||||
- name: arbiter
|
|
||||||
arbiter: true
|
|
||||||
- name: site-a
|
|
||||||
- name: site-b
|
|
||||||
```
|
|
||||||
|
|
||||||
> Mantén `placement.osd` restringido a `site-a`/`site-b` para no crear OSDs en el árbitro.
|
|
||||||
|
|
||||||
3. **(Opcional recomendado)** Cambia el `CephBlockPool` para que el *failure domain* vuelva a **`zone`** con `size: 4` (2 por zona). Si prefieres asegurar la regla, crea una CRUSH rule específica y asígnala al pool.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Ejemplo: regla por zona
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash -lc '
|
|
||||||
set -e
|
|
||||||
# Crea regla "rbd-4x-zone" (elige leaves de tipo zone)
|
|
||||||
ceph osd crush rule create-replicated rbd-4x-zone default zone || true
|
|
||||||
# Asigna la regla al pool y ajusta size
|
|
||||||
ceph osd pool set rbd-2x2-sites crush_rule rbd-4x-zone
|
|
||||||
ceph osd pool set rbd-2x2-sites size 4
|
|
||||||
ceph osd pool get rbd-2x2-sites crush_rule
|
|
||||||
'
|
|
||||||
```
|
|
||||||
|
|
||||||
> Tras el cambio a `zone`, Ceph reubica PGs para cumplir **2+2** entre `site-a` y `site-b`. Hazlo en ventana si ya hay mucho dato.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11) Troubleshooting rápido
|
|
||||||
|
|
||||||
* **PGs `active+undersized` con pool size=4**: ocurre si la regla CRUSH elige `zone` y solo hay 2 zonas (sin stretch). Solución: usa `failureDomain: host` o asigna una regla a `host` (sección 6) hasta activar stretch.
|
|
||||||
* **Ingress 503** al abrir el dashboard: el Service `rook-ceph-mgr-dashboard` usa **puerto 7000** (HTTP). Ajusta Ingress a `backend-protocol: "HTTP"` y puerto `7000`.
|
|
||||||
* **Cert TLS no emite**: revisa ClusterIssuer, DNS público hacia el Ingress y que el solver HTTP‑01 use `class: nginx`. Evita redirecciones que interfieran `/.well-known/acme-challenge/`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 12) Apéndice – Comandos útiles
|
|
||||||
|
|
||||||
Estado general:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph -s
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd tree
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph df
|
|
||||||
```
|
|
||||||
|
|
||||||
Ver pools y reglas:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd pool ls detail
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd pool get rbd-2x2-sites crush_rule
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd crush rule dump rbd-4x-host
|
|
||||||
```
|
|
||||||
|
|
||||||
Dashboard:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{.data.password}" | base64 -d; echo
|
|
||||||
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash -lc 'echo -n "NuevaPass" | ceph dashboard ac-user-set-password admin -i -'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
> **Resumen**: despliegas Rook‑Ceph con red de almacenamiento dedicada, discos por **by‑id**, pool RBD **size 4** sobre **host** para evitar PGs undersized sin árbitro, dashboard por **Ingress** (TLS en NGINX, backend HTTP:7000) y, cuando añadas el **árbitro**, pasas el clúster a **stretch** y el pool a **`failureDomain: zone`** con **2+2** por site.
|
## 11) Troubleshooting breve
|
||||||
|
|
||||||
|
* **MON no se reprograma** tras borrar uno: el operador necesita que el **quórum** quede seguro. Revisa `rook-ceph-mon-endpoints`, `deployment/rook-ceph-mon-*` y `op-mon` en logs del operador.
|
||||||
|
* **OSDs detectados como HDD** vía HBA: puedes forzar `deviceClass: ssd` por disco (como en el `CephCluster`) o, ya desplegado, ajustar con `ceph osd crush set-device-class ssd osd.N`.
|
||||||
|
* **Dashboard “Orchestrator is not available”**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph orch set backend rook
|
||||||
|
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph orch status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Fin
|
||||||
|
|
||||||
|
Con esto dispones de un despliegue Rook‑Ceph alineado con la realidad actual: 2 zonas de datos + árbitro, 3 MON (uno por zona), 2 MGR (A/B), OSDs solo en A/B, y un pool RBD con réplicas **2+2** por zona. ¡Listo para producción y ampliaciones futuras!
|
||||||
|
|||||||
4
seagate/csidriver/kustomization.yaml
Normal file
4
seagate/csidriver/kustomization.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- csi-exos-x-csidriver.yaml
|
||||||
8
seagate/kustomization.yaml
Normal file
8
seagate/kustomization.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- csidriver/
|
||||||
|
- secrets/
|
||||||
|
- storageclass/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Seagate Exos X CSI (ME5 dual‑site) — Guía de instalación y operación
|
# Seagate Exos X CSI (ME5 dual-site) — Guía de instalación y operación
|
||||||
|
|
||||||
Este README documenta cómo he dejado **reproducible** la instalación del *Seagate Exos X CSI Driver* (soporta ME5) en un clúster Kubernetes con **dos cabinas / dos zonas** (site‑a y site‑b) usando iSCSI + multipath y *topología por zona*.
|
Este README documenta cómo he dejado **reproducible** la instalación del *Seagate Exos X CSI Driver* (soporta ME5) en un clúster Kubernetes con **dos cabinas / dos zonas** (site-a y site-b) usando iSCSI + multipath y *topología por zona*.
|
||||||
|
|
||||||
> **Objetivo**
|
> **Objetivo**
|
||||||
>
|
>
|
||||||
@@ -11,11 +11,100 @@ Este README documenta cómo he dejado **reproducible** la instalación del *Seag
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Prerrequisitos en los nodos
|
## 1) Configuración iSCSI en los nodos
|
||||||
|
|
||||||
1. **Multipath** y **iSCSI** instalados/activos.
|
En **todos los nodos** del clúster:
|
||||||
|
|
||||||
2. **/etc/multipath.conf** — opciones relevantes usadas:
|
1. Instalar dependencias:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo zypper install open-iscsi yast2-iscsi-client multipath-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Habilitar y arrancar el servicio iSCSI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable --now iscsid.service
|
||||||
|
systemctl status iscsid.service
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Descubrir los targets en las cabinas:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo iscsiadm -m discovery -t sendtargets -p 192.168.3.11
|
||||||
|
sudo iscsiadm -m discovery -t sendtargets -p 192.168.3.21
|
||||||
|
```
|
||||||
|
|
||||||
|
En este punto hay que **añadir en las cabinas el grupo de host con cada host**.
|
||||||
|
|
||||||
|
4. Iniciar sesión contra todos los portales de ambas cabinas:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cabina site-a
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.11:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.12:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.13:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.14:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.15:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.16:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.17:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.18:3260 --login &
|
||||||
|
|
||||||
|
# Cabina site-b
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.21:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.22:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.23:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.24:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.25:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.26:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.27:3260 --login &
|
||||||
|
sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.28:3260 --login
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Verificar la sesión activa:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo iscsiadm -m session
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Editar configuración de iSCSI en `/etc/iscsi/iscsid.conf`:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
|
||||||
|
iscsid.safe_logout = Yes
|
||||||
|
node.startup = automatic
|
||||||
|
node.leading_login = No
|
||||||
|
node.session.timeo.replacement_timeout = 120
|
||||||
|
node.conn[0].timeo.login_timeout = 15
|
||||||
|
node.conn[0].timeo.logout_timeout = 15
|
||||||
|
node.conn[0].timeo.noop_out_interval = 5
|
||||||
|
node.conn[0].timeo.noop_out_timeout = 5
|
||||||
|
node.session.err_timeo.abort_timeout = 15
|
||||||
|
node.session.err_timeo.lu_reset_timeout = 30
|
||||||
|
node.session.err_timeo.tgt_reset_timeout = 30
|
||||||
|
node.session.err_timeo.host_reset_timeout = 60
|
||||||
|
node.session.initial_login_retry_max = 8
|
||||||
|
node.session.cmds_max = 128
|
||||||
|
node.session.queue_depth = 32
|
||||||
|
node.session.xmit_thread_priority = -20
|
||||||
|
node.session.iscsi.InitialR2T = No
|
||||||
|
node.session.iscsi.ImmediateData = Yes
|
||||||
|
node.session.iscsi.FirstBurstLength = 262144
|
||||||
|
node.session.iscsi.MaxBurstLength = 16776192
|
||||||
|
node.conn[0].iscsi.MaxRecvDataSegmentLength = 262144
|
||||||
|
node.conn[0].iscsi.MaxXmitDataSegmentLength = 0
|
||||||
|
discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768
|
||||||
|
node.session.nr_sessions = 1
|
||||||
|
node.session.reopen_max = 0
|
||||||
|
node.session.iscsi.FastAbort = Yes
|
||||||
|
node.session.scan = auto
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2) Prerrequisitos en los nodos
|
||||||
|
|
||||||
|
### 2.1. Configuración `/etc/multipath.conf`
|
||||||
|
|
||||||
```conf
|
```conf
|
||||||
defaults {
|
defaults {
|
||||||
@@ -37,23 +126,24 @@ devices {
|
|||||||
|
|
||||||
> **Por qué `greedy`?**
|
> **Por qué `greedy`?**
|
||||||
>
|
>
|
||||||
> * `find_multipaths "greedy"` evita crear *maps* hasta que haya más de un camino **o** el dispositivo sea claramente multipath, reduciendo falsos positivos y estabilizando el *udev settle*. Mejora tiempos de descubrimiento y evita *flapping*.
|
> * `find_multipaths "greedy"` evita crear *maps* hasta que haya más de un camino **o** el dispositivo sea claramente multipath, reduciendo falsos positivos y estabilizando el *udev settle*.
|
||||||
|
|
||||||
Reiniciar servicios y refrescar paths tras cambiar multipath:
|
|
||||||
|
### 2.2. Multipath e iSCSI activos
|
||||||
|
|
||||||
|
Asegurarse de tener `multipathd` en ejecución:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl restart multipathd
|
sudo systemctl restart multipathd
|
||||||
sudo multipath -r
|
sudo multipath -r
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Propagación de montajes (rshared)**
|
### 2.3. Propagación de montajes (rshared)
|
||||||
|
|
||||||
Asegurar que `/` y `/var/lib/kubelet` están en **rshared** para que los montajes hechos por el plugin dentro del pod del *node‑server* aparezcan en el host:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mount --make-rshared /
|
sudo mount --make-rshared /
|
||||||
|
|
||||||
# systemd drop‑in para kubelet
|
# systemd drop-in para kubelet
|
||||||
sudo install -d /etc/systemd/system/kubelet.service.d
|
sudo install -d /etc/systemd/system/kubelet.service.d
|
||||||
cat <<'EOF' | sudo tee /etc/systemd/system/kubelet.service.d/10-mount-propagation.conf
|
cat <<'EOF' | sudo tee /etc/systemd/system/kubelet.service.d/10-mount-propagation.conf
|
||||||
[Service]
|
[Service]
|
||||||
@@ -67,16 +157,14 @@ sudo systemctl daemon-reload
|
|||||||
sudo systemctl restart kubelet
|
sudo systemctl restart kubelet
|
||||||
```
|
```
|
||||||
|
|
||||||
Comprobar:
|
Verificar:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo findmnt -o TARGET,PROPAGATION /
|
sudo findmnt -o TARGET,PROPAGATION /
|
||||||
sudo findmnt -o TARGET,PROPAGATION /var/lib/kubelet
|
sudo findmnt -o TARGET,PROPAGATION /var/lib/kubelet
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Etiquetas de topología en nodos**
|
### 2.4. Etiquetas de topología en nodos
|
||||||
|
|
||||||
Etiquetar cada nodo con su zona:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl label nodes <nodo-del-site-a> topology.kubernetes.io/zone=site-a --overwrite
|
kubectl label nodes <nodo-del-site-a> topology.kubernetes.io/zone=site-a --overwrite
|
||||||
@@ -85,30 +173,9 @@ kubectl label nodes <nodo-del-site-b> topology.kubernetes.io/zone=site-b --overw
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) Despliegue del Driver con Helm
|
## 3) Despliegue del Driver con Helm
|
||||||
|
|
||||||
### 2.1. Namespace y valores
|
### 3.1. Instalación
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f namespace.yaml # namespace: seagate
|
|
||||||
```
|
|
||||||
|
|
||||||
**values.yaml** (resumen de lo usado):
|
|
||||||
|
|
||||||
* Imagen del driver: `ghcr.io/seagate/seagate-exos-x-csi:v1.10.0`
|
|
||||||
* Sidecars:
|
|
||||||
|
|
||||||
* `csi-provisioner v5.0.1` (timeout 60s)
|
|
||||||
* `csi-attacher v4.6.1`
|
|
||||||
* `csi-resizer v1.11.1`
|
|
||||||
* `csi-snapshotter v8.0.1`
|
|
||||||
* `csi-node-driver-registrar v2.9.0`
|
|
||||||
* `controller.extraArgs: ["-v=2"]`
|
|
||||||
* `node.extraArgs: ["-v=2"]`
|
|
||||||
|
|
||||||
> **Nota:** no es necesario tocar `CSIDriver` para topología; la topología se maneja desde los `StorageClass` + etiquetas de nodo.
|
|
||||||
|
|
||||||
### 2.2. Instalación
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm upgrade --install exos-x-csi \
|
helm upgrade --install exos-x-csi \
|
||||||
@@ -117,69 +184,41 @@ helm upgrade --install exos-x-csi \
|
|||||||
-f ./values.yaml
|
-f ./values.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Si hay residuos de una instalación anterior (RBAC)
|
*(Si hay residuos RBAC, eliminarlos antes de reintentar)*
|
||||||
|
|
||||||
Si aparece un error de *invalid ownership metadata* con recursos tipo `ClusterRole/ClusterRoleBinding` de un release previo (p.ej. `exosx-csi`), eliminarlos:
|
|
||||||
|
### 3.2. Namespace y valores
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl delete clusterrole external-provisioner-runner-systems
|
kubectl apply -k .
|
||||||
kubectl delete clusterrolebinding csi-provisioner-role-systems
|
|
||||||
# (si hubiera más, listarlos por label y borrarlos)
|
|
||||||
# kubectl get clusterrole,clusterrolebinding -A -l app.kubernetes.io/instance=<old-release>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Reintentar `helm upgrade --install`.
|
Esto asegura que se creen en el orden correcto:
|
||||||
|
|
||||||
|
1. `namespace.yaml` → crea el namespace seagate.
|
||||||
|
2. `csidriver/` → instala el recurso CSIDriver (cluster-scoped).
|
||||||
|
3. `secrets/` → instala los secrets de conexión en el namespace seagate.
|
||||||
|
4. `storageclass/` → instala los dos StorageClass (sc-me5-site-a y sc-me5-site-b).
|
||||||
|
|
||||||
|
>Notas sobre recursos cluster-scoped:
|
||||||
|
En Kubernetes hay recursos que pertenecen a un namespace (ej: Pod, Secret, ConfigMap) y otros que son globales para todo el clúster (ej: CSIDriver, StorageClass, Node, Namespace). Los resources namespaced se pueden repetir en distintos namespaces. Los cluster-scoped solo existen una vez en todo el clúster y no tienen campo namespace.
|
||||||
|
En este repositorio:
|
||||||
|
|
||||||
|
* CSIDriver y StorageClass son cluster-scoped → no tienen namespace.
|
||||||
|
* Los Secret sí son namespaced → se instalan en seagate.
|
||||||
|
|
||||||
|
Por eso el kustomization.yaml está separado en subcarpetas:
|
||||||
|
|
||||||
|
* secrets/kustomization.yaml tiene namespace: seagate porque aplica solo a objetos namespaced.
|
||||||
|
* csidriver/ y storageclass/ no tienen namespace porque son cluster-scoped.
|
||||||
|
|
||||||
|
Esto evita errores y mantiene la instalación GitOps-friendly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) Secret por cabina (A y B)
|
## 4) Prueba de extremo a extremo
|
||||||
|
|
||||||
Un `Secret` por sitio en el *namespace* `seagate` con `apiAddress`, `username`, `password` en Base64.
|
PVC + Pod en site-a:
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f secret-me5-site-a.yaml
|
|
||||||
kubectl apply -f secret-me5-site-b.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Importante:** Los `StorageClass` deben usar las **claves estándar CSI** para que el provisioner pase el Secret al driver:
|
|
||||||
>
|
|
||||||
> * `csi.storage.k8s.io/provisioner-secret-name|namespace`
|
|
||||||
> * `csi.storage.k8s.io/controller-publish-secret-name|namespace`
|
|
||||||
> * `csi.storage.k8s.io/controller-expand-secret-name|namespace`
|
|
||||||
> * `csi.storage.k8s.io/node-stage-secret-name|namespace` *(si aplica)*
|
|
||||||
> * `csi.storage.k8s.io/node-publish-secret-name|namespace` *(si aplica)*
|
|
||||||
|
|
||||||
El síntoma de no usar estos nombres es: `missing API credentials` en el evento del PVC.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4) StorageClass por zona (topología)
|
|
||||||
|
|
||||||
Se definen **dos** `StorageClass` idénticos salvo:
|
|
||||||
|
|
||||||
* Secret (A o B)
|
|
||||||
* `pool` (p. ej., `dg01` para site‑a, `dg02` para site‑b)
|
|
||||||
* `volPrefix` (ej. `sza` / `szb` para identificar site en el nombre de LUN)
|
|
||||||
* `allowedTopologies` con la zona correspondiente
|
|
||||||
* `volumeBindingMode: WaitForFirstConsumer`
|
|
||||||
|
|
||||||
> Con WFFC, el PVC **no** se enlaza hasta que exista un Pod consumidor; el scheduler elige un nodo, y el provisioner crea el volumen en la **zona del nodo**.
|
|
||||||
|
|
||||||
Aplicar ambos `StorageClass`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f sc-me5-site-a.yaml
|
|
||||||
kubectl apply -f sc-me5-site-b.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5) Prueba de extremo a extremo
|
|
||||||
|
|
||||||
### 5.1. PVC + Pod en site‑a
|
|
||||||
|
|
||||||
* PVC: `pvc-a` con `storageClassName: sc-me5-site-a`
|
|
||||||
* Pod: `pod-a` con `nodeSelector: topology.kubernetes.io/zone=site-a`
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f pvc-pod-a.yaml
|
kubectl apply -f pvc-pod-a.yaml
|
||||||
@@ -187,115 +226,47 @@ kubectl apply -f pod-a.yaml
|
|||||||
kubectl get pvc,pod
|
kubectl get pvc,pod
|
||||||
```
|
```
|
||||||
|
|
||||||
Deberías ver el Pod en *Running* y el volumen creado/montado en la ME5 del site‑a.
|
Verificar `iscsiadm`, `multipath`, eventos del PVC y logs del controller.
|
||||||
|
|
||||||
### 5.2. Verificaciones útiles
|
|
||||||
|
|
||||||
* **iSCSI nodes vistos:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo iscsiadm -m node | sort
|
|
||||||
```
|
|
||||||
|
|
||||||
* **Multipath:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo multipath -ll
|
|
||||||
```
|
|
||||||
|
|
||||||
* **Eventos del PVC:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl describe pvc <nombre>
|
|
||||||
```
|
|
||||||
|
|
||||||
* **Logs del controller:** (búsqueda de credenciales / errores de provisión)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n seagate logs deploy/seagate-exos-x-csi-controller-server \
|
|
||||||
-c seagate-exos-x-csi-controller | grep -i -E 'cred|secret|error'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Medir el tiempo de *NodePublish* (montaje)
|
## 5) Medición de tiempos de *NodePublish*
|
||||||
|
|
||||||
Para medir cuánto tarda el montaje (fase *NodePublishVolume*) desde el *node‑server*:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n seagate logs -l name=seagate-exos-x-csi-node-server \
|
kubectl -n seagate logs -l name=seagate-exos-x-csi-node-server \
|
||||||
-c seagate-exos-x-csi-node --tail=10000 \
|
-c seagate-exos-x-csi-node --tail=10000 \
|
||||||
| grep "NodePublishVolume" \
|
| grep "NodePublishVolume" | grep "ROUTINE END"
|
||||||
| grep "ROUTINE END" \
|
|
||||||
| sed -E 's/.*NodePublishVolume.*<([^>]*)>.*/\1/'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* Valores \~**< 2 min** indican que el montaje completa dentro de la ventana de kubelet, evitando `DeadlineExceeded`.
|
---
|
||||||
* Si ves \~**4m34s** constantes: el driver está esperando a que aparezcan *dm‑name* de portales inaccesibles. Revisa topologías, conectividad y que solo se prueben portales de la zona activa.
|
|
||||||
|
|
||||||
> Para validar zona‑B, lanza un Pod/PVC análogo en `site-b` y repite el grep anterior en los logs.
|
## 6) Solución de problemas
|
||||||
|
|
||||||
|
* `missing API credentials` → revisar claves CSI en el StorageClass.
|
||||||
|
* `DeadlineExceeded` → revisar multipath, etiquetas de zona y topología.
|
||||||
|
* Helm RBAC conflict → borrar roles residuales.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Solución de problemas
|
## 7) Limpieza
|
||||||
|
|
||||||
* **`missing API credentials` al provisionar**
|
|
||||||
|
|
||||||
* Asegúrate de usar las **claves CSI** en `parameters:` del `StorageClass` (ver §3).
|
|
||||||
|
|
||||||
* **Errores Helm de *invalid ownership metadata***
|
|
||||||
|
|
||||||
* Borra los `ClusterRole/ClusterRoleBinding` residuales del release antiguo (ver §2.2).
|
|
||||||
|
|
||||||
* **`DeadlineExceeded` durante montaje**
|
|
||||||
|
|
||||||
* Comprueba:
|
|
||||||
|
|
||||||
* `find_multipaths "greedy"` y resto de multipath según §1.2.
|
|
||||||
* Etiquetas de zona en el nodo donde programa el Pod.
|
|
||||||
* Que el `StorageClass` correcto tenga `allowedTopologies` de esa zona.
|
|
||||||
|
|
||||||
* **Ver puertos/portales iSCSI efectivos**
|
|
||||||
|
|
||||||
* `sudo iscsiadm -m node | sort` para ver a qué destinos quedó configurado el nodo. Con topología bien aplicada, deben ser los del sitio correspondiente.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8) Limpieza y reintentos
|
|
||||||
|
|
||||||
Para repetir la prueba desde cero (manteniendo el driver):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl delete -f pod-a.yaml
|
kubectl delete -f pod-a.yaml
|
||||||
kubectl delete -f pvc-pod-a.yaml
|
kubectl delete -f pvc-pod-a.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Si quisieras limpiar *todo el despliegue* del driver:
|
Para desinstalar completamente:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm uninstall exos-x-csi -n seagate
|
helm uninstall exos-x-csi -n seagate
|
||||||
# Si quedaron RBAC de releases previos:
|
|
||||||
kubectl delete clusterrole external-provisioner-runner-systems || true
|
|
||||||
kubectl delete clusterrolebinding csi-provisioner-role-systems || true
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Resumen de lo que quedó en repo (carpeta `seagate/`)
|
## 8) Anexos — Comandos útiles
|
||||||
|
|
||||||
* `namespace.yaml` — Namespace `seagate`.
|
* Reinicio multipath/kubelet
|
||||||
* `secret-me5-site-a.yaml` / `secret-me5-site-b.yaml` — Credenciales por sitio.
|
* Limpieza iSCSI/multipath:
|
||||||
* `values.yaml` — Valores de Helm usados para el driver v1.10.0.
|
|
||||||
* `sc-me5-site-a.yaml` / `sc-me5-site-b.yaml` — StorageClass con `allowedTopologies`, `pool`, `volPrefix`, claves CSI de Secret y `WaitForFirstConsumer`.
|
|
||||||
* `pvc-pod-a.yaml` + `pod-a.yaml` — Manifests de prueba en `site-a`.
|
|
||||||
* *(Opcional)* `csi-exos-x-csidriver.yaml` — no es necesario modificarlo para topología en esta versión.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10) Anexos — Comandos útiles ejecutados
|
|
||||||
|
|
||||||
* Reinicio multipath/kubelet y propagación de montajes.
|
|
||||||
* Limpieza iSCSI/multipath (cuando se rehizo la prueba):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo iscsiadm -m node -u || true
|
sudo iscsiadm -m node -u || true
|
||||||
@@ -303,14 +274,3 @@ sudo iscsiadm -m node -o delete || true
|
|||||||
sudo multipath -F || true
|
sudo multipath -F || true
|
||||||
sudo multipath -r
|
sudo multipath -r
|
||||||
```
|
```
|
||||||
|
|
||||||
* Despliegue Helm + manejo de residuos RBAC (ver §2.2).
|
|
||||||
* Aplicación secuencial de `namespace`, `secrets`, `StorageClass`, `PVC` y `Pod`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Resultado
|
|
||||||
|
|
||||||
* **Reproducible**: con esta receta, el volumen se crea en la cabina de su zona y el Pod arranca.
|
|
||||||
* **Tiempos de montaje**: bajan de \~4m34s a **≈1m30s** (observado), dentro del presupuesto de kubelet.
|
|
||||||
* **Aislamiento por zona**: cada StorageClass limita portales iSCSI a su sitio gracias a `allowedTopologies` + etiquetas de nodo.
|
|
||||||
|
|||||||
5
seagate/secrets/kustomization.yaml
Normal file
5
seagate/secrets/kustomization.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- secret-me5-site-a.yaml
|
||||||
|
- secret-me5-site-b.yaml
|
||||||
5
seagate/storageclass/kustomization.yaml
Normal file
5
seagate/storageclass/kustomization.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- sc-me5-site-a.yaml
|
||||||
|
- sc-me5-site-b.yaml
|
||||||
@@ -3,7 +3,8 @@ kind: StorageClass
|
|||||||
metadata:
|
metadata:
|
||||||
name: sc-me5-site-a
|
name: sc-me5-site-a
|
||||||
provisioner: csi-exos-x.seagate.com
|
provisioner: csi-exos-x.seagate.com
|
||||||
volumeBindingMode: WaitForFirstConsumer
|
reclaimPolicy: Delete
|
||||||
|
volumeBindingMode: Immediate
|
||||||
allowVolumeExpansion: true
|
allowVolumeExpansion: true
|
||||||
parameters:
|
parameters:
|
||||||
csi.storage.k8s.io/provisioner-secret-name: seagate-me5-site-a
|
csi.storage.k8s.io/provisioner-secret-name: seagate-me5-site-a
|
||||||
@@ -13,10 +14,7 @@ parameters:
|
|||||||
csi.storage.k8s.io/controller-expand-secret-name: seagate-me5-site-a
|
csi.storage.k8s.io/controller-expand-secret-name: seagate-me5-site-a
|
||||||
csi.storage.k8s.io/controller-expand-secret-namespace: seagate
|
csi.storage.k8s.io/controller-expand-secret-namespace: seagate
|
||||||
csi.storage.k8s.io/fstype: ext4
|
csi.storage.k8s.io/fstype: ext4
|
||||||
pool: dg01 # pool de la ME5 del Site A
|
pool: pool
|
||||||
volPrefix: sza # prefijo corto para identificar Site A
|
volPrefix: sza
|
||||||
storageProtocol: iscsi
|
storageProtocol: iscsi
|
||||||
allowedTopologies:
|
|
||||||
- matchLabelExpressions:
|
|
||||||
- key: topology.kubernetes.io/zone
|
|
||||||
values: ["site-a"]
|
|
||||||
@@ -3,7 +3,8 @@ kind: StorageClass
|
|||||||
metadata:
|
metadata:
|
||||||
name: sc-me5-site-b
|
name: sc-me5-site-b
|
||||||
provisioner: csi-exos-x.seagate.com
|
provisioner: csi-exos-x.seagate.com
|
||||||
volumeBindingMode: WaitForFirstConsumer
|
reclaimPolicy: Delete
|
||||||
|
volumeBindingMode: Immediate
|
||||||
allowVolumeExpansion: true
|
allowVolumeExpansion: true
|
||||||
parameters:
|
parameters:
|
||||||
csi.storage.k8s.io/provisioner-secret-name: seagate-me5-site-b
|
csi.storage.k8s.io/provisioner-secret-name: seagate-me5-site-b
|
||||||
@@ -13,10 +14,6 @@ parameters:
|
|||||||
csi.storage.k8s.io/controller-expand-secret-name: seagate-me5-site-b
|
csi.storage.k8s.io/controller-expand-secret-name: seagate-me5-site-b
|
||||||
csi.storage.k8s.io/controller-expand-secret-namespace: seagate
|
csi.storage.k8s.io/controller-expand-secret-namespace: seagate
|
||||||
csi.storage.k8s.io/fstype: ext4
|
csi.storage.k8s.io/fstype: ext4
|
||||||
pool: dg02
|
pool: pool
|
||||||
volPrefix: szb
|
volPrefix: szb
|
||||||
storageProtocol: iscsi
|
storageProtocol: iscsi
|
||||||
allowedTopologies:
|
|
||||||
- matchLabelExpressions:
|
|
||||||
- key: topology.kubernetes.io/zone
|
|
||||||
values: ["site-b"]
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: test-http
|
|
||||||
# annotations:
|
|
||||||
# metallb.universe.tf/address-pool: default
|
|
||||||
spec:
|
|
||||||
# type: NodePort
|
|
||||||
type: LoadBalancer
|
|
||||||
loadBalancerIP: 192.168.200.10
|
|
||||||
selector:
|
|
||||||
app: test-http
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
# nodePort: 30080
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: test-http
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: test-http
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: test-http
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: test-http
|
|
||||||
image: nginx:alpine
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
16
velero/backupstoragelocations/bsl-a.yaml
Normal file
16
velero/backupstoragelocations/bsl-a.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: velero.io/v1
|
||||||
|
kind: BackupStorageLocation
|
||||||
|
metadata:
|
||||||
|
name: bsl-incluster-a
|
||||||
|
spec:
|
||||||
|
provider: aws
|
||||||
|
objectStorage:
|
||||||
|
bucket: velero-backups
|
||||||
|
config:
|
||||||
|
s3Url: http://minio-a.minio-velero.svc.cluster.local:9000
|
||||||
|
s3ForcePathStyle: "true"
|
||||||
|
region: site-a
|
||||||
|
accessMode: ReadWrite
|
||||||
|
credential:
|
||||||
|
name: cloud-credentials
|
||||||
|
key: cloud
|
||||||
16
velero/backupstoragelocations/bsl-b.yaml
Normal file
16
velero/backupstoragelocations/bsl-b.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: velero.io/v1
|
||||||
|
kind: BackupStorageLocation
|
||||||
|
metadata:
|
||||||
|
name: bsl-incluster-b
|
||||||
|
spec:
|
||||||
|
provider: aws
|
||||||
|
objectStorage:
|
||||||
|
bucket: velero-backups
|
||||||
|
config:
|
||||||
|
s3Url: http://minio-b.minio-velero.svc.cluster.local:9000
|
||||||
|
s3ForcePathStyle: "true"
|
||||||
|
region: site-b
|
||||||
|
accessMode: ReadWrite
|
||||||
|
credential:
|
||||||
|
name: cloud-credentials
|
||||||
|
key: cloud
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
apiVersion: velero.io/v1
|
|
||||||
kind: BackupStorageLocation
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
namespace: velero
|
|
||||||
spec:
|
|
||||||
provider: aws
|
|
||||||
objectStorage:
|
|
||||||
bucket: velero
|
|
||||||
config:
|
|
||||||
region: minio
|
|
||||||
s3Url: https://s3-a.c2et.net
|
|
||||||
s3ForcePathStyle: "true"
|
|
||||||
credential:
|
|
||||||
name: cloud-credentials-site-a
|
|
||||||
key: cloud
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
apiVersion: velero.io/v1
|
|
||||||
kind: BackupStorageLocation
|
|
||||||
metadata:
|
|
||||||
name: site-b
|
|
||||||
namespace: velero
|
|
||||||
spec:
|
|
||||||
provider: aws
|
|
||||||
objectStorage:
|
|
||||||
bucket: velero
|
|
||||||
config:
|
|
||||||
region: minio
|
|
||||||
s3Url: https://s3-b.c2et.net
|
|
||||||
s3ForcePathStyle: "true"
|
|
||||||
credential:
|
|
||||||
name: cloud-credentials-site-b
|
|
||||||
key: cloud
|
|
||||||
47
velero/deployments/minio-a.yaml
Normal file
47
velero/deployments/minio-a.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: minio-a
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
app.kubernetes.io/instance: minio-a
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
app.kubernetes.io/instance: minio-a
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
app.kubernetes.io/instance: minio-a
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: minio
|
||||||
|
image: quay.io/minio/minio:latest
|
||||||
|
args: ["server", "/data", "--console-address", ":9001"]
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: minio-root
|
||||||
|
ports:
|
||||||
|
- name: s3
|
||||||
|
containerPort: 9000
|
||||||
|
- name: console
|
||||||
|
containerPort: 9001
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "250m"
|
||||||
|
memory: "512Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: "4Gi"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: minio-a-data
|
||||||
47
velero/deployments/minio-b.yaml
Normal file
47
velero/deployments/minio-b.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: minio-b
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
app.kubernetes.io/instance: minio-b
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
app.kubernetes.io/instance: minio-b
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
app.kubernetes.io/instance: minio-b
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: minio
|
||||||
|
image: quay.io/minio/minio:latest
|
||||||
|
args: ["server", "/data", "--console-address", ":9001"]
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: minio-root
|
||||||
|
ports:
|
||||||
|
- name: s3
|
||||||
|
containerPort: 9000
|
||||||
|
- name: console
|
||||||
|
containerPort: 9001
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "250m"
|
||||||
|
memory: "512Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: "4Gi"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: minio-b-data
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
credentials:
|
|
||||||
useSecret: true
|
|
||||||
existingSecret: ""
|
|
||||||
secretContents:
|
|
||||||
cloud: |
|
|
||||||
[default]
|
|
||||||
aws_access_key_id=velero-a
|
|
||||||
aws_secret_access_key=Clave-Velero-A
|
|
||||||
|
|
||||||
configuration:
|
|
||||||
features: EnableCSI
|
|
||||||
backupStorageLocation:
|
|
||||||
- name: default
|
|
||||||
provider: aws
|
|
||||||
bucket: velero
|
|
||||||
config:
|
|
||||||
region: minio
|
|
||||||
s3Url: https://s3-a.c2et.net
|
|
||||||
s3ForcePathStyle: "true"
|
|
||||||
|
|
||||||
initContainers:
|
|
||||||
- name: velero-plugin-for-aws
|
|
||||||
image: velero/velero-plugin-for-aws:v1.9.0
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
volumeMounts:
|
|
||||||
- name: plugins
|
|
||||||
mountPath: /target
|
|
||||||
- name: velero-plugin-for-csi
|
|
||||||
image: velero/velero-plugin-for-csi:v0.7.0
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
volumeMounts:
|
|
||||||
- name: plugins
|
|
||||||
mountPath: /target
|
|
||||||
|
|
||||||
nodeAgent:
|
|
||||||
enabled: true
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# values-combined.yaml
|
|
||||||
credentials:
|
|
||||||
useSecret: false # Secrets y BSLs los aplicas tú por YAML (como ya hiciste)
|
|
||||||
|
|
||||||
configuration:
|
|
||||||
features: ""
|
|
||||||
backupStorageLocation: [] # ninguno desde Helm (los gestionas por YAML)
|
|
||||||
defaultVolumesToFsBackup: true # copia datos de PV vía node-agent/Kopia al BSL
|
|
||||||
|
|
||||||
# Dejamos SOLO el plugin de AWS; el CSI externo se quita (viene integrado en Velero 1.16)
|
|
||||||
initContainers:
|
|
||||||
- name: velero-plugin-for-aws
|
|
||||||
image: velero/velero-plugin-for-aws:v1.9.0
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
volumeMounts:
|
|
||||||
- name: plugins
|
|
||||||
mountPath: /target
|
|
||||||
|
|
||||||
# **activar** el node-agent (DaemonSet) y darle tolerations "catch-all"
|
|
||||||
deployNodeAgent: true
|
|
||||||
nodeAgent:
|
|
||||||
podConfig:
|
|
||||||
tolerations:
|
|
||||||
- key: "node-role.kubernetes.io/master"
|
|
||||||
operator: "Exists"
|
|
||||||
effect: "NoSchedule"
|
|
||||||
- key: "node-role.kubernetes.io/control-plane"
|
|
||||||
operator: "Exists"
|
|
||||||
effect: "NoSchedule"
|
|
||||||
- operator: "Exists" # tolera cualquier otro taint
|
|
||||||
50
velero/jobs/minio-a-init.yaml
Normal file
50
velero/jobs/minio-a-init.yaml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: minio-a-init
|
||||||
|
namespace: minio-velero
|
||||||
|
spec:
|
||||||
|
backoffLimit: 3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: init
|
||||||
|
image: bitnami/minio-client:latest
|
||||||
|
command: ["/bin/sh","-lc"]
|
||||||
|
env:
|
||||||
|
- name: MINIO_ENDPOINT
|
||||||
|
value: "http://minio-a.minio-velero.svc.cluster.local:9000"
|
||||||
|
- name: MINIO_ROOT_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-root
|
||||||
|
key: MINIO_ROOT_USER
|
||||||
|
- name: MINIO_ROOT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-root
|
||||||
|
key: MINIO_ROOT_PASSWORD
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
set -euo pipefail
|
||||||
|
echo "[init-a] waiting for $MINIO_ENDPOINT ..."
|
||||||
|
until curl -sf "$MINIO_ENDPOINT/minio/health/ready" >/dev/null; do sleep 2; done
|
||||||
|
echo "[init-a] configuring bucket/user/policy"
|
||||||
|
mc alias set minioA "$MINIO_ENDPOINT" "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"
|
||||||
|
mc mb minioA/velero-backups || true
|
||||||
|
mc version enable minioA/velero-backups || true
|
||||||
|
mc admin user add minioA velero Velero12345 || true
|
||||||
|
cat > /tmp/policy.json <<'EOF'
|
||||||
|
{ "Version":"2012-10-17",
|
||||||
|
"Statement":[
|
||||||
|
{"Effect":"Allow","Action":["s3:*"],
|
||||||
|
"Resource":["arn:aws:s3:::velero-backups","arn:aws:s3:::velero-backups/*"]}
|
||||||
|
]}
|
||||||
|
EOF
|
||||||
|
mc admin policy create minioA velero-rw /tmp/policy.json || true
|
||||||
|
mc admin policy attach minioA velero-rw --user velero || true
|
||||||
|
echo "[init-a] verifying with velero creds"
|
||||||
|
mc alias set a-vel "$MINIO_ENDPOINT" velero Velero12345
|
||||||
|
mc ls a-vel/velero-backups >/dev/null
|
||||||
|
echo "[init-a] done"
|
||||||
50
velero/jobs/minio-b-init.yaml
Normal file
50
velero/jobs/minio-b-init.yaml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: minio-b-init
|
||||||
|
namespace: minio-velero
|
||||||
|
spec:
|
||||||
|
backoffLimit: 3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: init
|
||||||
|
image: bitnami/minio-client:latest
|
||||||
|
command: ["/bin/sh","-lc"]
|
||||||
|
env:
|
||||||
|
- name: MINIO_ENDPOINT
|
||||||
|
value: "http://minio-b.minio-velero.svc.cluster.local:9000"
|
||||||
|
- name: MINIO_ROOT_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-root
|
||||||
|
key: MINIO_ROOT_USER
|
||||||
|
- name: MINIO_ROOT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: minio-root
|
||||||
|
key: MINIO_ROOT_PASSWORD
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
set -euo pipefail
|
||||||
|
echo "[init-b] waiting for $MINIO_ENDPOINT ..."
|
||||||
|
until curl -sf "$MINIO_ENDPOINT/minio/health/ready" >/dev/null; do sleep 2; done
|
||||||
|
echo "[init-b] configuring bucket/user/policy"
|
||||||
|
mc alias set minioB "$MINIO_ENDPOINT" "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"
|
||||||
|
mc mb minioB/velero-backups || true
|
||||||
|
mc version enable minioB/velero-backups || true
|
||||||
|
mc admin user add minioB velero Velero12345 || true
|
||||||
|
cat > /tmp/policy.json <<'EOF'
|
||||||
|
{ "Version":"2012-10-17",
|
||||||
|
"Statement":[
|
||||||
|
{"Effect":"Allow","Action":["s3:*"],
|
||||||
|
"Resource":["arn:aws:s3:::velero-backups","arn:aws:s3:::velero-backups/*"]}
|
||||||
|
]}
|
||||||
|
EOF
|
||||||
|
mc admin policy create minioB velero-rw /tmp/policy.json || true
|
||||||
|
mc admin policy attach minioB velero-rw --user velero || true
|
||||||
|
echo "[init-b] verifying with velero creds"
|
||||||
|
mc alias set b-vel "$MINIO_ENDPOINT" velero Velero12345
|
||||||
|
mc ls b-vel/velero-backups >/dev/null
|
||||||
|
echo "[init-b] done"
|
||||||
21
velero/kustomization.yaml
Normal file
21
velero/kustomization.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
namespace: minio-velero
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- secrets/minio-root.yaml
|
||||||
|
- secrets/cloud-credentials.yaml
|
||||||
|
- networkpolicies/default-deny-ingress.yaml
|
||||||
|
- networkpolicies/allow-self-to-minio.yaml
|
||||||
|
- pvcs/minio-a-pvc.yaml
|
||||||
|
- deployments/minio-a.yaml
|
||||||
|
- services/minio-a.yaml
|
||||||
|
- jobs/minio-a-init.yaml
|
||||||
|
- pvcs/minio-b-pvc.yaml
|
||||||
|
- deployments/minio-b.yaml
|
||||||
|
- services/minio-b.yaml
|
||||||
|
- jobs/minio-b-init.yaml
|
||||||
|
- backupstoragelocations/bsl-a.yaml
|
||||||
|
- backupstoragelocations/bsl-b.yaml
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"annotations": {
|
|
||||||
"list": []
|
|
||||||
},
|
|
||||||
"editable": true,
|
|
||||||
"gnetId": null,
|
|
||||||
"graphTooltip": 0,
|
|
||||||
"panels": [
|
|
||||||
{
|
|
||||||
"type": "stat",
|
|
||||||
"title": "Backups - Total",
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"expr": "sum(velero_backup_total)",
|
|
||||||
"legendFormat": "total"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": 1,
|
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "prometheus"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"reduceOptions": {
|
|
||||||
"calcs": [
|
|
||||||
"lastNotNull"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "timeSeries",
|
|
||||||
"title": "Backups por estado",
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"expr": "sum by (phase) (increase(velero_backup_attempt_total[1h]))",
|
|
||||||
"legendFormat": "{{phase}}"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": 2,
|
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "prometheus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "timeSeries",
|
|
||||||
"title": "Duraci\u00f3n de backups (p95)",
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"expr": "histogram_quantile(0.95, sum(rate(velero_backup_duration_seconds_bucket[5m])) by (le))",
|
|
||||||
"legendFormat": "p95"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": 3,
|
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "prometheus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "timeSeries",
|
|
||||||
"title": "Errores del node-agent",
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"expr": "sum(rate(velero_node_agent_errors_total[5m]))",
|
|
||||||
"legendFormat": "errores"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": 4,
|
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "prometheus"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"schemaVersion": 37,
|
|
||||||
"style": "dark",
|
|
||||||
"tags": [
|
|
||||||
"velero",
|
|
||||||
"backup"
|
|
||||||
],
|
|
||||||
"templating": {
|
|
||||||
"list": []
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"from": "now-24h",
|
|
||||||
"to": "now"
|
|
||||||
},
|
|
||||||
"title": "Velero (MinIO S3)",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
apiVersion: monitoring.coreos.com/v1
|
|
||||||
kind: ServiceMonitor
|
|
||||||
metadata:
|
|
||||||
name: velero
|
|
||||||
namespace: velero
|
|
||||||
labels:
|
|
||||||
release: prometheus # ajusta al selector de tu Prometheus
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app.kubernetes.io/name: velero
|
|
||||||
namespaceSelector:
|
|
||||||
matchNames: ["velero"]
|
|
||||||
endpoints:
|
|
||||||
- port: metrics
|
|
||||||
interval: 30s
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: velero
|
name: minio-velero
|
||||||
|
|||||||
19
velero/networkpolicies/allow-self-to-minio.yaml
Normal file
19
velero/networkpolicies/allow-self-to-minio.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-self-to-minio
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: minio
|
||||||
|
policyTypes: ["Ingress"]
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: minio-velero
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 9000
|
||||||
|
- protocol: TCP
|
||||||
|
port: 9001
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user