k3s: Portainer CE mit übernommener Datenbank von appsrv08 (Manifest + Playbook mit Rollback BE→CE)
ci / test (push) Failing after 24s
ci / test (push) Failing after 24s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
26e1079f3d
commit
4d31dda0e5
@@ -0,0 +1,95 @@
|
|||||||
|
# Portainer CE im Cluster, Umzug von appsrv08 (Portainer EE 2.45.1) mit übernommener Datenbank (Benutzer,
|
||||||
|
# API-Schlüssel, Umgebungen, Stacks). Läuft auf der Dienst-VM k3s (tank, HA), Daten auf local-path dieser VM.
|
||||||
|
# Erst-Befüllung und Rollback BE→CE macht playbooks/portainer-k3s.yml aus /root/.config/knaster/portainer_data.tgz.
|
||||||
|
# Erreichbar: https://<Knoten-IP>:30779 (NodePort), von außen über den nginx auf appsrv08 (portainer.mygodel.de).
|
||||||
|
# Dieselbe Version wie auf appsrv08 (2.45.1): die Datenbank wird beim Start nicht migriert.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: portainer-ce
|
||||||
|
labels:
|
||||||
|
knaster.app: portainer
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: portainer-data
|
||||||
|
namespace: portainer-ce
|
||||||
|
spec:
|
||||||
|
accessModes: [ReadWriteOnce]
|
||||||
|
storageClassName: local-path
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
|
---
|
||||||
|
# Portainer verwaltet den eigenen Cluster über ein ServiceAccount (Umgebung „local“ wird beim ersten Start angelegt).
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: portainer-sa-clusteradmin
|
||||||
|
namespace: portainer-ce
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: portainer-ce-crb
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: cluster-admin
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: portainer-sa-clusteradmin
|
||||||
|
namespace: portainer-ce
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: portainer
|
||||||
|
namespace: portainer-ce
|
||||||
|
labels: {app: portainer-ce}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy: {type: Recreate}
|
||||||
|
selector:
|
||||||
|
matchLabels: {app: portainer-ce}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels: {app: portainer-ce}
|
||||||
|
spec:
|
||||||
|
serviceAccountName: portainer-sa-clusteradmin
|
||||||
|
nodeSelector:
|
||||||
|
knaster.role: control # Dienst-VM k3s: tank, HA, Replikation
|
||||||
|
containers:
|
||||||
|
- name: portainer
|
||||||
|
image: portainer/portainer-ce:2.45.1
|
||||||
|
ports:
|
||||||
|
- {name: https, containerPort: 9443}
|
||||||
|
- {name: edge, containerPort: 8000}
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 50m, memory: 128Mi}
|
||||||
|
limits: {memory: 512Mi}
|
||||||
|
volumeMounts:
|
||||||
|
- {name: data, mountPath: /data}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet: {path: /api/system/status, port: https, scheme: HTTPS}
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet: {path: /api/system/status, port: https, scheme: HTTPS}
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim: {claimName: portainer-data}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: portainer
|
||||||
|
namespace: portainer-ce
|
||||||
|
labels: {app: portainer-ce}
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
selector: {app: portainer-ce}
|
||||||
|
ports:
|
||||||
|
- {name: https, port: 9443, targetPort: https, nodePort: 30779}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# Portainer CE in k3s mit der Datenbank von appsrv08 (Portainer EE 2.45.1). Läuft auf ops:
|
||||||
|
# ansible-playbook playbooks/portainer-k3s.yml
|
||||||
|
#
|
||||||
|
# Voraussetzung: Sicherung des Docker-Volumes portainer_data von appsrv08 als /root/.config/knaster/portainer_data.tgz
|
||||||
|
# (Inhalt: data/portainer.db, data/portainer.key, …; erzeugt mit
|
||||||
|
# docker run --rm -v portainer_data:/data:ro alpine tar -C / -czf - data > portainer_data.tgz ).
|
||||||
|
# Beim ersten Lauf wird das Volume befüllt und die Datenbank mit dem offiziellen Werkzeug der EE
|
||||||
|
# (`--rollback-to-ce`) auf Community Edition zurückgesetzt; danach bleibt der Datenstand im Cluster.
|
||||||
|
# Benutzer, API-Schlüssel und Umgebungen bleiben erhalten (getestet 15.10.2026). Die Umgebung 4 (Docker-Socket
|
||||||
|
# von appsrv08) funktioniert im Cluster nicht mehr; appsrv08 wird als Agent-Umgebung neu angebunden.
|
||||||
|
- name: Portainer CE nach k3s
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
vars:
|
||||||
|
manifest: "{{ playbook_dir }}/../../../../deploy/k8s/portainer/portainer.yaml"
|
||||||
|
backup: /root/.config/knaster/portainer_data.tgz
|
||||||
|
ns: portainer-ce
|
||||||
|
version: 2.45.1
|
||||||
|
tasks:
|
||||||
|
- name: Namespace, PVC, RBAC (noch ohne Deployment, damit das Volume zuerst befüllt wird)
|
||||||
|
ansible.builtin.shell: >
|
||||||
|
set -o pipefail;
|
||||||
|
python3 -c "import sys,yaml; docs=[d for d in yaml.safe_load_all(open('{{ manifest }}')) if d and d['kind']!='Deployment' and d['kind']!='Service']; yaml.safe_dump_all(docs, sys.stdout)"
|
||||||
|
| kubectl apply -f -
|
||||||
|
args: {executable: /bin/bash}
|
||||||
|
register: base
|
||||||
|
changed_when: "'created' in base.stdout"
|
||||||
|
|
||||||
|
- name: Ist das Volume schon befüllt?
|
||||||
|
ansible.builtin.command: kubectl -n {{ ns }} get configmap portainer-seeded
|
||||||
|
register: seeded
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Sicherung vorhanden?
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ backup }}"
|
||||||
|
register: bk
|
||||||
|
when: seeded.rc != 0
|
||||||
|
failed_when: not bk.stat.exists
|
||||||
|
|
||||||
|
- name: Volume aus der Sicherung befüllen (Hilfs-Pod auf dem Knoten k3s)
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -e
|
||||||
|
kubectl -n {{ ns }} delete pod seed --ignore-not-found >/dev/null
|
||||||
|
cat <<EOF | kubectl apply -f - >/dev/null
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata: {name: seed, namespace: {{ ns }}}
|
||||||
|
spec:
|
||||||
|
nodeSelector: {knaster.role: control}
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: seed
|
||||||
|
image: alpine:3.20
|
||||||
|
command: ["sleep", "600"]
|
||||||
|
volumeMounts: [{name: data, mountPath: /data}]
|
||||||
|
volumes: [{name: data, persistentVolumeClaim: {claimName: portainer-data}}]
|
||||||
|
EOF
|
||||||
|
kubectl -n {{ ns }} wait --for=condition=Ready pod/seed --timeout=180s >/dev/null
|
||||||
|
kubectl -n {{ ns }} cp {{ backup }} seed:/tmp/pd.tgz
|
||||||
|
kubectl -n {{ ns }} exec seed -- sh -c "cd /tmp && tar xzf pd.tgz && cp -a data/. /data/ && test -s /data/portainer.db"
|
||||||
|
kubectl -n {{ ns }} delete pod seed --wait=true >/dev/null
|
||||||
|
when: seeded.rc != 0
|
||||||
|
|
||||||
|
- name: Datenbank auf Community Edition zurücksetzen (offizielles Werkzeug der EE, fragt per stdin)
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -e
|
||||||
|
kubectl -n {{ ns }} delete pod rollback --ignore-not-found >/dev/null
|
||||||
|
echo y | kubectl -n {{ ns }} run rollback -i --restart=Never --image=portainer/portainer-ee:{{ version }} \
|
||||||
|
--overrides='{"spec":{"nodeSelector":{"knaster.role":"control"},"containers":[{"name":"rollback","image":"portainer/portainer-ee:{{ version }}","args":["--rollback-to-ce"],"stdin":true,"volumeMounts":[{"name":"data","mountPath":"/data"}]}],"volumes":[{"name":"data","persistentVolumeClaim":{"claimName":"portainer-data"}}]}}' >/dev/null 2>&1 || true
|
||||||
|
sleep 5
|
||||||
|
kubectl -n {{ ns }} logs rollback | grep -q "rolled back to CE Edition"
|
||||||
|
kubectl -n {{ ns }} delete pod rollback --wait=false >/dev/null
|
||||||
|
kubectl -n {{ ns }} create configmap portainer-seeded --from-literal=source={{ backup | basename }} --from-literal=date="$(date -Is)"
|
||||||
|
when: seeded.rc != 0
|
||||||
|
|
||||||
|
- name: Deployment und Service
|
||||||
|
ansible.builtin.command: kubectl apply -f {{ manifest }}
|
||||||
|
register: dep
|
||||||
|
changed_when: "'configured' in dep.stdout or 'created' in dep.stdout"
|
||||||
|
|
||||||
|
- name: Warten, bis bereit
|
||||||
|
ansible.builtin.command: kubectl -n {{ ns }} rollout status deployment/portainer --timeout=300s
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Version und Edition über NodePort (Knoten k3s)
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "https://{{ hostvars['k3s'].ansible_host }}:30779/api/system/version"
|
||||||
|
validate_certs: false
|
||||||
|
return_content: true
|
||||||
|
register: ver
|
||||||
|
until: ver.status == 200
|
||||||
|
retries: 6
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Ergebnis
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ver.json.ServerEdition == 'CE'
|
||||||
|
- ver.json.ServerVersion == version
|
||||||
|
success_msg: "Portainer {{ ver.json.ServerEdition }} {{ ver.json.ServerVersion }} unter https://{{ hostvars['k3s'].ansible_host }}:30779"
|
||||||
Reference in New Issue
Block a user