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