Velero (anteprima)
lionbackup sta diventando una destinazione di storage per
Velero, lo strumento di backup per Kubernetes. A questo
scopo esiste un plugin che registra lionbackup come provider di
BackupStorageLocation, e un piccolo controller nel cluster che carica ogni
backup completato come un unico file cifrato in un progetto lionbackup.
Entrambi sono disponibili come beta 0.2.0-beta.1: da provare in un
cluster di test, non ancora come unico backup.
Ciò che arriva a lionbackup è lo spool: manifest Kubernetes, metadati e log del backup. Il contenuto dei volumi (PVC) non viene ancora salvato; un PVC torna come definizione, ma vuoto. Per i dati dei volumi continuate ad affidarvi a un'altra via.
Cosa fa oggi l'anteprima, e cosa no
| Funziona oggi | Manca ancora |
|---|---|
Velero funziona completamente contro uno spool nel cluster: backup e ripristino dei manifest, sync, GC, backup delete | Dati dei volumi: il contenuto dei PVC non viene catturato (il node-agent di Velero conosce solo s3, azure, gcs e file system) |
URL firmati: velero backup logs e describe --details funzionano, i backup terminano Completed | Import del ripristino: il bundle torna nello spool dall'esterno del cluster (client con token di lettura) |
Upload: il controller raggruppa backups/<nome>/ in un solo .lbk, lo carica con un token di scrittura e annota il backup con il file_id | Job di cattura e ripristino dei volumi; nuovi tentativi solo come "di nuovo tra 10 minuti" |
Un backup Failed significa che non è stato scritto nulla; di solito il
proprietario della directory di spool è sbagliato (vedi passo 1). Un
PartiallyFailed si verifica solo se manca il controller o il segreto URL
condiviso (passo 4).
Provarlo
Servono un cluster di test, kubectl, la CLI di Velero (testata con Velero
1.18.3), un progetto lionbackup con un token di scrittura e il client
lionbackup sulla propria postazione per la coppia di chiavi. L'immagine del
plugin si scarica senza credenziali.
1. Creare la directory di spool
Velero scrive in una directory del nodo, montata nel pod di Velero come
hostPath (o come PVC). L'immagine ufficiale di Velero gira con l'ID utente
1002; fsGroup non si applica a un hostPath, quindi la directory deve
appartenere a quell'ID. Altrimenti ogni backup fallisce con permission denied pur segnalando tutti gli oggetti come salvati; l'errore compare solo
in status.failureReason.
mkdir -p /var/lib/lionbackup/spool
chown -R 1002:1002 /var/lib/lionbackup/spool
chmod 775 /var/lib/lionbackup/spool
2. Installare Velero con il plugin
velero install \
--provider lionbackup.cloud/lionbackup \
--plugins git.prod.lionbackup.cloud/lionbackup/velero-plugin-lionbackup:0.2.0-beta.1 \
--bucket spool \
--no-secret \
--use-volume-snapshots=false \
--backup-location-config spoolPath=/var/lib/lionbackup/spool \
--wait
--no-secret è corretto: il plugin in sé non ha bisogno di credenziali. Il
token di scrittura va nel Secret del controller (passo 4), mai sulla
BackupStorageLocation.
3. Montare lo spool nel pod di Velero
kubectl -n velero patch deployment velero --type=json -p '[
{"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"lionbackup-spool","hostPath":{"path":"/var/lib/lionbackup/spool","type":"DirectoryOrCreate"}}},
{"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"lionbackup-spool","mountPath":"/var/lib/lionbackup/spool"}}
]'
kubectl -n velero rollout status deploy/velero --timeout=180s
kubectl -n velero get backupstoragelocation default
Senza questo passo lo spool vive nel file system del pod e sparisce al
riavvio successivo. La BackupStorageLocation dovrebbe poi riportare
Available.
4. Controller e Secret
Il controller gira nella stessa immagine come utente 1002, con lo spool
montato in sola lettura e il Secret in /etc/lionbackup. Gli servono tre
cose: il token di scrittura del progetto, un segreto URL casuale condiviso con
il pod di Velero e la chiave pubblica per la cifratura. Generate la coppia
di chiavi sulla vostra postazione; la chiave privata non entra mai nel cluster
e senza di essa non c'è ripristino.
lionbackup --generate-key --key-name ./velero
kubectl -n velero create secret generic lionbackup-velero \
--from-literal=token=<WRITE-TOKEN> \
--from-literal=url-secret="$(head -c 32 /dev/urandom | base64)" \
--from-file=key.pub=./velero.pub
Salvate il manifest seguente come controller.yaml. Contiene ServiceAccount,
Role, RoleBinding, Service e Deployment; la directory di lavoro /work deve
poter contenere la directory di backup più grande dello spool.
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: lionbackup-velero-controller
namespace: velero
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: lionbackup-velero-controller
namespace: velero
rules:
- apiGroups: ["velero.io"]
resources: ["backups"]
verbs: ["get", "list", "watch", "patch"]
- apiGroups: ["velero.io"]
resources: ["backupstoragelocations"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: lionbackup-velero-controller
namespace: velero
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: lionbackup-velero-controller
subjects:
- kind: ServiceAccount
name: lionbackup-velero-controller
namespace: velero
---
apiVersion: v1
kind: Service
metadata:
name: lionbackup-velero-controller
namespace: velero
spec:
selector:
app.kubernetes.io/name: lionbackup-velero-controller
ports:
- name: http
port: 8080
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: lionbackup-velero-controller
namespace: velero
labels:
app.kubernetes.io/name: lionbackup-velero-controller
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: lionbackup-velero-controller
template:
metadata:
labels:
app.kubernetes.io/name: lionbackup-velero-controller
spec:
serviceAccountName: lionbackup-velero-controller
securityContext:
runAsUser: 1002
runAsGroup: 1002
runAsNonRoot: true
containers:
- name: controller
image: git.prod.lionbackup.cloud/lionbackup/velero-plugin-lionbackup:0.2.0-beta.1
command: ["/plugins/velero-plugin-lionbackup"]
args: ["controller"]
ports:
- name: http
containerPort: 8080
env:
- name: VELERO_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LIONBACKUP_SPOOL_PATH
value: /var/lib/lionbackup/spool
- name: LIONBACKUP_KEYFILE
value: /etc/lionbackup/key.pub
- name: LIONBACKUP_WORKDIR
value: /work
- name: LIONBACKUP_TOKEN
valueFrom:
secretKeyRef:
name: lionbackup-velero
key: token
- name: LIONBACKUP_VELERO_URL_SECRET
valueFrom:
secretKeyRef:
name: lionbackup-velero
key: url-secret
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 3
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: "2"
memory: 1Gi
volumeMounts:
- name: lionbackup-spool
mountPath: /var/lib/lionbackup/spool
readOnly: true
- name: lionbackup-secret
mountPath: /etc/lionbackup
readOnly: true
- name: work
mountPath: /work
volumes:
- name: lionbackup-spool
hostPath:
path: /var/lib/lionbackup/spool
type: Directory
- name: lionbackup-secret
secret:
secretName: lionbackup-velero
items:
- key: key.pub
path: key.pub
- name: work
emptyDir:
sizeLimit: 10Gi
Poi applicatelo, passate il segreto URL anche al deployment di Velero e
impostate progetto e zona sulla BackupStorageLocation:
kubectl apply -f controller.yaml
kubectl -n velero set env deployment/velero \
LIONBACKUP_VELERO_URL_SECRET="$(kubectl -n velero get secret lionbackup-velero -o jsonpath='{.data.url-secret}' | base64 -d)"
kubectl -n velero patch backupstoragelocation default --type=merge -p \
'{"spec":{"config":{"lbProject":"<PROJECT-UUID>","lbZone":"de01-1","lbEnvironment":"prod"}}}'
kubectl -n velero rollout status deploy/velero --timeout=180s
kubectl -n velero rollout status deploy/lionbackup-velero-controller --timeout=180s
Senza token o chiave il controller registra nel log solo ciò che caricherebbe
(observe-only). Altre chiavi config della BackupStorageLocation:
lbCompressionMethod (ZSTD), lbCompressionLevel (5), lbChunksizeMb
(64), lbUploadRateLimitMbit (0 = illimitato).
Gli URL firmati puntano al Service del controller nel cluster, quindi velero backup logs e describe --details funzionano dove quel Service è
raggiungibile. Se la CLI di Velero gira fuori dal cluster, inoltrate la porta
(kubectl -n velero port-forward svc/lionbackup-velero-controller 8080:8080)
e impostate controllerURL sulla BackupStorageLocation a
http://localhost:8080; la firma copre solo percorso e scadenza, non l'host.
5. Backup
velero backup create demo-1 --include-namespaces demo-app --wait
velero backup logs demo-1 | tail -n 3
kubectl -n velero get backup demo-1 \
-o jsonpath='{.status.phase} {.metadata.annotations.lionbackup\.cloud/file-id}{"\n"}'
È atteso Completed, e velero backup logs restituisce il log tramite l'URL
firmato del controller. Poco dopo l'oggetto Backup porta l'annotazione
lionbackup.cloud/file-id: l'identificativo del file caricato nel progetto,
lo stesso mostrato da --list del client. Se l'upload fallisce, il motivo è
nel log del controller, che riprova dopo dieci minuti.
6. Ripristino da lionbackup
La via del ritorno inizia fuori dal cluster, con un token di lettura e la
chiave privata; entrambi restano così lontani dal cluster. Il client scarica
il bundle, copiate la directory del backup nello spool del cluster di
destinazione e Velero la raccoglie alla sincronizzazione successiva della
BackupStorageLocation:
lionbackup --config read.yaml --list
lionbackup --config read.yaml --restore <FILE-ID> --identity ./velero.key --target ./restored
# ./restored/…/backups/demo-1/ -> <spoolPath>/spool/backups/demo-1/ des Zielclusters
velero restore create demo-restore --from-backup demo-1 --wait
Manifest, deployment, ConfigMap e definizioni dei PVC tornano. I dati nei volumi no; è il limite documentato dell'anteprima.
Cosa viene dopo
La fase successiva salva il contenuto dei volumi: un job per PVC sul nodo del
pod trasmette il volume come archivio nello spool, un job di ripristino
corrispondente lo riempie di nuovo e un init container trattiene
l'applicazione finché il volume non è di nuovo disponibile. A ciò si aggiunge
un endpoint del controller che riporta un bundle tramite file_id
direttamente nello spool. Fino ad allora vale la nota all'inizio di questa
pagina.