Files
cluster-knaster/platform/proxmox/ansible/playbooks/portainer-k3s.yml
T

104 lines
5.0 KiB
YAML

# 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"