Normale Ansicht

Es gibt neue verfügbare Artikel. Klicken Sie, um die Seite zu aktualisieren.
Ältere BeiträgeHaupt-Feeds

Mein Paperless-NGX-Mini-Konzept

31. Juli 2023 um 05:00

Paperless-NGX ist ein bekanntes und beliebtes Open Source Dokumenten-Management-System (DMS). Auch ich möchte zukünftig meinen „Papierkram“ darin verwalten.

In diesem Artikel halte ich meine Gedanken fest, wie ich plane, paperless-ngx in meiner Umgebung aufzusetzen und zu betreiben.

Dies hilft mir, zu prüfen, ob ich auch an alles Wichtige gedacht habe. Falls euch das Konzept gefällt, dürft ihr es selbstverständlich gerne nachahmen. Und wenn ihr schwerwiegende Fehler darin entdeckt, freue ich mich über einen Hinweis.

Es ist kein Tutorial und keine Schritt-für-Schritt-Anleitung. Zwar mag dieser Text dazu dienen, sich eine eigene Umgebung aufzubauen, Mitdenken ist dabei jedoch zwingend erforderlich.

Ziele

  • Betrieb von Paperless-NGX als rootless-Podman-Container
  • Consumption-Ordner als Samba-Share freigegeben, um via Netzwerk Dateien hineinkopieren zu können
  • Getrennte Benutzerkonten für meine Frau und mich
  • Freigabe gewisser Dokumente für weitere Benutzer(gruppen)
  • Erfolgreicher Restore-Test

Infrastruktur

In meinem Heimnetzwerk betreibe ich einen Desktop-/Server-PC. Auf diesem läuft aktuell RHEL 9 als KVM/QEMU-Hypervisor. Er dient mir ebenfalls als Ansible Control Node. Hierauf betreibe ich eine RHEL-9-VM mit einer rootless-Podman-Installation. Diese VM wird auch meine Paperless-NGX-Instanz hosten.

In der VM wird das EPEL-Repository aktiviert, um daraus die Pakete podman-compose und python3-pexpect installieren zu können.

Falls ich mal nicht mehr weiß, wie dieses Setup aufgebaut wird, finden sich dazu Hinweise in folgenden Links:

Installation mit Ansible

Für die Installation der Anwendung wird die Container Route verwendet. Die Installation wird dabei unter Nutzung der Ansible-Rolle tronde.paperless_ngx_with_rootless_podman automatisiert.

Das Playbook deploy_paperless_ngx.yml, welches auf meiner Synology Diskstation abgelegt ist, führt die Installation und Konfiguration der Anwendung durch. Es installiert und konfiguriert zudem Samba und die Datei-Freigabe des Consumption-Verzeichnisses.

In dem Playbook werden folgende Rollen verwendet:

Die Rollen sind mit dem Playbook in meinem Ansible-Projekt-Verzeichnis auf meiner Synology Diskstation installiert.

Alle Playbooks und Rollen werden mit Git versioniert. Die Repositories werden auf entfernte Rechner synchronisiert.

Vorbereitung

Die Dateien docker-compose.postgres-tika.yml, docker-compose.env und .env werden aus dem Projekt-Repository in das Rollen-Verzeichnis files meiner Ansible-Rolle heruntergeladen. Die Datei docker-compose.postgres-tika.yml wird dabei zu docker-compose.yml umbenannt und bearbeitet.

Um Datenverlust vorzubeugen, wird die Ansible-Rolle mit den angepassten Dateien in die regelmäßige Datensicherung aufgenommen.

Folgende Variablen werden in meinem Ansible-Vault hinterlegt:

# Paperless-ngx with podman-compose
pnwrp_podman_user: alice
pnwrp_podman_group: alice
pnwrp_compose_dir: /home/{{ pnwrp_podman_user }}/paperless-ngx
pnwrp_paperless_superuser: alice
pnwrp_paperless_superuser_email: alice@example.com
pnwrp_paperless_superuser_password: ImWunderland
## Username and password for document scanner
brother_scanner_user: scanner
brother_scanner_pass: ImWunderland

Die Werte der Variablen werden selbstverständlich angepasst.

Das Playbook

Folgender Code-Block zeigt das fertige Playbook mit Beispielwerten:

---
- hosts: host.example.com
  remote_user: alice
  debugger: never
  vars_files:
    - files/alice.vault
  tasks:
    - name: Setup Paperless-NGX with podman-compose in rootless Podman
      include_role:
        name: ansible_role_paperless-ngx_with_rootless_podman

    - name: Enable Port 8000/tcp in host firewall
      ansible.posix.firewalld:
        port: 8000/tcp
        immediate: true
        permanent: true
        state: enabled
      become: true

    - name: >-
        Create and add {{ brother_scanner_user }} to
        {{ pnwrp_podman_group }}
      ansible.builtin.user:
        name: "{{ brother_scanner_user }}"
        comment: "Brother Dokumenten-Scanner"
        create_home: false
        groups: "{{ pnwrp_podman_group }}"
        append: true
        shell: /usr/sbin/nologin
        state: present
        system: true
      become: true

    - name: Include role vladgh.samba.server
      include_role:
        name: vladgh.samba.server
      vars:
        ansible_become: true
        samba_users:
          - name: "{{ pnwrp_podman_user }}"
            password: "{{ alice_password }}"
          - name: "{{ brother_scanner_user }}"
            password: "{{ brother_scanner_pass }}"
        samba_shares:
          - name: consumption
            comment: 'paperless consumption directory'
            path: "{{ pnwrp_compose_dir }}/consume"
            read_only: false
            guest_ok: false
            browseable: true
            owner: "{{ pnwrp_podman_user }}"
            group: "{{ pnwrp_podman_group }}"
            write_list: +{{ pnwrp_podman_group }}

    - name: Enable samba in host firewall
      ansible.posix.firewalld:
        service: samba
        immediate: true
        permanent: true
        state: enabled
      become: true

Das Playbook gewinnt sicher keinen Schönheitswettbewerb, doch arbeitet es bisher robust und tut, was es soll. In Tests habe ich meine Wunschumgebung damit mehrmals provisioniert.

Backup & Restore

Wie es sich gehört, wird erst ein Backup erstellt, dann die Anwendung inkl. aller Daten gelöscht und wiederhergestellt.

Backup

Für das Backup verwende ich ein Ansible-Playbook, welches sich zum Podman-Host verbindet und dort folgende Aufgaben ausführt:

  1. Stelle sicher, dass das Backup-Verzeichnis auf dem Remote-Host existiert
  2. Stoppe alle Paperless-NGX-Container
  3. Exportiere Podman-Volumes in TAR-Archive; hänge das aktuelle Datum an die Dateinamen an
  4. Archiviere und komprimiere paperless-ngx-Verzeichnis auf Remote-Host; hänge das aktuelle Datum an die Dateinamen an
  5. Starte alle Paperless-NGX-Container
  6. Komprimiere die Exporte der Podman-Volumes
  7. Synchronisiere das Backup-Verzeichnis auf dem Remote-Host mit einem Verzeichnis auf meiner Diskstation
  8. Synchronisiere das Diskstation-Verzeichnis mit einem verschlüsselten S3-Bucket

Es fehlt die Aufgabe, alte Backups aufzuräumen. Darum werde ich mich kümmern, wenn 70% des verfügbaren Speicherplatzes belegt sind.

Der folgende Code-Block zeigt ein Muster des verwendeten Playbooks:

---
- name: Backup podman volumes
  hosts: host.example.com
  gather_facts: true
  vars:
    paperless_ngx_dir: /home/alice/paperless-ngx
    docker_compose_file: docker-compose.yml
    remote_backup_dir: /home/alice/backups
    diskstation_backup_dir: /home/alice/diskstation/home/backups/host.example.com

  tasks:
    - name: Ensure backup directory exists
      ansible.builtin.file:
        path: "{{ remote_backup_dir }}"
        state: directory
        owner: alice
        group: alice
        mode: 0777

    - name: Stop paperless-ngx containers
      ansible.builtin.command: >
        podman-compose -f {{ paperless_ngx_dir }}/{{ docker_compose_file }} stop

    - name: List podman volumes
      ansible.builtin.command: podman volume ls --quiet
      register: __podman_volumes
      tags:
        - volumes

    - name: Output __podman_volumes
      ansible.builtin.debug:
        msg: "{{ item }}"
      loop: "{{ __podman_volumes['stdout_lines'] }}"
      tags:
        - volumes

    - name: Export podman volumes
      ansible.builtin.command: >
        podman volume export {{ item }} --output {{ remote_backup_dir }}/{{ item }}_{{ ansible_facts['date_time']['date'] }}.tar
      loop: "{{ __podman_volumes['stdout_lines'] }}"

    - name: Compact {{ paperless_ngx_dir }}
      community.general.archive:
        path: "{{ paperless_ngx_dir }}"
        dest: "{{ remote_backup_dir }}/paperless-ngx_{{ ansible_facts['date_time']['date'] }}.tar.gz"
        format: gz

    - name: Start paperless-ngx containers
      ansible.builtin.command: >
        podman-compose -f {{ paperless_ngx_dir }}/{{ docker_compose_file }} start

    - name: Compress volume exports
      community.general.archive:
        path: "{{ remote_backup_dir }}/{{ item }}_{{ ansible_facts['date_time']['date'] }}.tar"
        format: gz
        remove: true
      loop: "{{ __podman_volumes['stdout_lines'] }}"
      tags:
        - compress

    - name: Sync backups to diskstation
      ansible.posix.synchronize:
        archive: true
        compress: false
        delete: false
        dest: "{{ diskstation_backup_dir }}"
        mode: pull
        private_key: /home/alice/.ssh/ansible_id_rsa
        src: "{{ remote_backup_dir }}/"
      delegate_to: localhost
      tags:
        - rsync

    - name: Sync backups from diskstation to contabo S3
      ansible.builtin.command: rclone sync -P ../backups/ secure:backups
      delegate_to: localhost
      tags:
        - rsync

Das Playbook wird einmal wöchentlich ausgeführt. Ob ich für die geplante Ausführung cron oder systemd timer units verwende, habe ich noch nicht entschieden. Ich tendiere aus Neugier zu letzterem.

Um ein Offsite-Backup zu haben, werden die Dateien von der Diskstation einmal wöchentlich verschlüsselt und in einen S3-Speicher synchronisiert. Ich nutze dafür das Programm rclone und S3-kompatiblen Speicher von Contabo. Die folgenden Links bieten weiterführende Informationen dazu:

Restore

Der Ablaufplan für die Wiederherstellung der Anwendung mit ihren Daten sieht wie folgt aus:

  1. Eine rootless-Podman-Umgebung bereitstellen
  2. podman-compose bereitstellen
  3. TAR-Archive auf Zielsystem übertragen
  4. Paperless-NGX mit Playbook installieren
  5. Alle Container stoppen
  6. Inhalt der TAR-Archive in die Podman-Volumes importieren (siehe podman-volume-import(1)): gunzip -c hello.tar.gz | podman volume import myvol -
  7. Alle Container starten

Fazit

Bereitstellung, Sicherung und Wiederherstellung funktionieren wie beschrieben. Damit kann ich nun beginnen und die Anwendung konfigurieren und mit meinem Papierkram füttern.

Die Samba-Freigabe habe ich ebenfalls getestet. Sie funktioniert wie erwartet. PDF-Dateien mit dem Befehl find Documents -type f -iname "*.pdf" -exec cp {} /consume \; hineinzukopieren ist übrigens besonders dann eine gute Idee, wenn man sehen möchte, welche Dateien so in den Tiefen des eigenen Dateisystems schlummern.

Ansible: Seafile Professional Edition in Rootless-Podman-Umgebung bereitstellen

20. März 2023 um 06:00

Wer diesen Blog regelmäßig liest, kann den Eindruck gewinnen, es sei mein Hobby, Ansible-Rollen zu schreiben, mit denen von mir genutzte Web-Anwendungen auf Servern bereitgestellt werden können. Dieses Mal habe ich es mit Seafile getan und möchte in diesem Beitrag darüber berichten.

Was ist Seafile?

Seafile ist eine Sync&Share- bzw. Private-Cloud-Lösung ähnlich wie Nextcloud, ownCloud oder TeamDrive. Auf mich erweckt Seafile den Eindruck, als wenn der Schwerpunkt jedoch auf der Synchronisation und dem Teilen von Dateien liegt und damit genau meinem Suchmuster entspricht.

Seafile gibt es in einer Community und einer Professional Edition. Die Professional Edition darf mit bis zu drei Benutzern kostenlos verwendet werden.

Für weiterführende Informationen wird auf die Seiten des Herstellers und den Wikipedia-Artikel verwiesen.

Was ist das Ziel?

Nun, es gibt nicht das eine Ziel. Ich habe mit diesem kleinen Wochenendprojekt folgende Ziele verfolgt:

  • Beschäftige dich mit Ansible.
  • Beschäftige dich mit der Collection Containers.Podman.
  • Beschäftige dich mit rootless Podman.
  • Deploye Seafile Professional Edition in einer rootless-Podman-Umgebung, um es als Sync&Share-Lösung nutzen zu können.

Die Vorgehensweise

Zuerst habe ich mich informiert, ob es Container-Images für Seafile gibt und ob entsprechende Installationswege in der Dokumentation beschrieben sind. Meine Recherche förderte folgende Treffer zutage:

Ansible-Rollen haben eine einheitliche Struktur. Mit dem Befehl ansible-galaxy role init ansible_role_deploy_seafile_with_rootless_podman habe ich das Grundgerüst für meine Rolle erstellt. Anschließend habe ich die notwendigen Dateien {defaults,meta,tasks,vars}/main.yml mit Inhalt gefüllt und nicht benötigte Verzeichnisse wie handlers gelöscht. Mir ist dabei wichtig, dass alle notwendigen Parameter über Variablen definiert werden, die in defaults/main.yml zu finden sind. In vars/main.yml befinden sich hingegen nur Variablen, welche intern von der Rolle verwendet werden und vom Benutzer nicht explizit gesetzt werden sollen. So lässt sich die Rolle leicht wiederverwenden, um verschiedene Seafile-Instanzen auf dem gleichen Host oder in unterschiedlichen Umgebungen zu deployen.

Bevor ich die Rolle zum ersten Mal auf meinen Server angewendet habe, habe ich sie mit yamllint und ansible-lint geprüft und vorhandene Warnungen und Fehler behoben. Allerdings lassen sich mit den Lint-Werkzeugen und der Option --syntax-check nicht alle Fehler im Vorfeld finden. Da mir ein zweites Augenpaar fehlte, habe ich die letzten Tippfehler erst durch die Verwendung des Ansible Playbook Debugger gefunden.

Das Ergebnis

Das Ergebnis findet ihr auf:

Unter allen drei URLs könnt ihr meine Rolle herunterladen. Es ist damit möglich, eine lauffähige Seafile Pro Instanz bereitzustellen. Ein Test auf Idempotenz und ob diese Rolle auch zur Aktualisierung einer bestehenden Umgebung genutzt werden kann, steht noch aus.

Ihr seid herzlich eingeladen, die Rolle bei Interesse zu testen. Ich freue mich über Rückmeldungen zur Rolle und Dokumentation (Readme.md).

Ich habe das Deployment bisher nur auf Debian Buster getestet. Daher freue ich mich besonders über Rückmeldungen, wenn ihr die Rolle erfolgreich auf anderen Plattformen angewendet habt. Dann kann ich die entsprechenden Angaben für Ansible Galaxy ergänzen.

Eure Rückmeldungen nehme ich in den Kommentaren zu diesem Beitrag, per E-Mail oder in meinem neuen Matrix-Kanal #my-it-brain:matrix.org entgegen.

Fragen an meine Leser*innen

Ich interessiere mich für Themen rund um Ansible und Podman und frage mich, wie dies bei euch aussieht. Daher freue ich mich, wenn ihr in den Kommentaren oder gern auch per E-Mail und Chat folgende Fragen beantworten mögt:

  • Verwendet ihr Ansible für Software-Deployments?
  • Kennt ihr Podman und nutzt ihr es im privaten und/oder beruflichen Umfeld?
  • Findet ihr die Nutzung von Ansible zur Bereitstellung von Software auf (rootless) Podman sinnvoll? Oder bevorzugt ihr andere Bereitstellungsverfahren?

Ich freue mich auf eure Antworten.

❌
❌