From ab8c51a57d872eb03cdc2b4c4eef33ea6af2d948 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Tue, 8 Sep 2026 22:59:56 +0200 Subject: [PATCH] Migrate Prometheus stack to Podman --- AGENTS.md | 15 +++++--- README.it.md | 12 ++++-- README.md | 11 ++++-- .../inventory/group_vars/platform_rocky.yml | 8 ++-- ansible/inventory/group_vars/rocky_server.yml | 31 ++++------------ ansible/inventory/group_vars/server.yml | 8 ---- ansible/roles/packages_rocky/tasks/main.yml | 37 +++++-------------- .../roles/profile_server/handlers/main.yml | 5 +++ ansible/roles/profile_server/tasks/main.yml | 17 ++------- .../profile_server/tasks/podman-compose.yml | 10 +++++ .../podman-compose-server.service.j2 | 15 ++++++++ .../templates/server/docker-compose.yml.j2 | 17 ++++----- dotfiles/common/.bashrc.aliases | 3 ++ 13 files changed, 91 insertions(+), 98 deletions(-) create mode 100644 ansible/roles/profile_server/tasks/podman-compose.yml create mode 100644 ansible/roles/profile_server/templates/podman-compose-server.service.j2 diff --git a/AGENTS.md b/AGENTS.md index 7f1652c..208f3b3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -52,7 +52,7 @@ Ansible-driven personal infrastructure repo for Fedora and Void desktops, Fedora - Emacs is disabled by default; temporary Emacs check: `ansible-playbook ansible/site.yml --limit --tags emacs --check --diff -e emacs_enabled=true` - AI coding agents: `ansible-playbook ansible/site.yml --limit --tags ai_agents --check --diff` - Mail bootstrap: `sh -n scripts/bootstrap_mail.sh` and `shellcheck scripts/bootstrap_mail.sh` - - Server compose render: `docker compose -f /opt/docker/server/docker-compose.yml config` + - Server compose render: `podman-compose -f /opt/docker/server/docker-compose.yml config` and `systemctl status podman-compose-server` - DuckDNS config only: `ansible-playbook ansible/site.yml --limit prometheus --tags duckdns --check --diff` ## Conventions @@ -103,12 +103,17 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-i and disables diffs. Provisioning does not execute the updater or change its external schedule. - `rocky_server` is a child of both `platform_rocky` and `server`; `prometheus` is its active target. - The target must already provide `server_username` with local sudo access before the profile runs. -- The Rocky profile installs Docker CE, uses firewalld, preserves SELinux enforcement, and renders the - same server Compose stack. It does not transfer data, start containers, update DNS, or cut over traffic. +- The Rocky profile installs Podman and podman-compose, uses firewalld, preserves SELinux enforcement, and renders the + same server Compose stack with a `podman-compose-server` systemd unit. It does not start, enable, transfer data, + update DNS, or cut over traffic; activating the stack is a manual step. +- Firewalld enables SSH, Cockpit (`9090/tcp`), HTTP and HTTPS. Nginx Proxy Manager publishes `80/tcp` and + `443/tcp`; bind its administration interface only to `127.0.0.1:81` and use `npm-tunnel` from Ikaros or Nymph. + Nextcloud remains disabled; do not provision `/srv/nextcloud` directories. - `scripts/migrate_prometheus_data.sh` is the separate, source-host-run migration path. It dry-runs by default and requires explicit source-stack quiescing before copying persistent Docker data with rsync. -- Atlas-only OpenZFS, NFS, Samba, Cockpit, and Syncthing stay selected through Atlas host variables - and must not leak into `rocky_server`. +- Atlas-only OpenZFS, NFS, Samba, and Syncthing stay selected through Atlas host variables and must not + leak into `rocky_server`. Cockpit plus its Navigator and Podman extensions are selected explicitly for + Prometheus through its host variables. ## Atlas NAS Notes - `atlas` is a remote Rocky Linux 9 NAS. Keep its connection, LAN, pool and mountpoint values in diff --git a/README.it.md b/README.it.md index 1dcba60..664c877 100644 --- a/README.it.md +++ b/README.it.md @@ -178,12 +178,16 @@ Profilo orientato a servizi server e gestione di dotfiles dedicati. Lo stato attuale del profilo server include: - installazione pacchetti Rocky via DNF, EPEL e CRB -- installazione e configurazione di Docker dal repository ufficiale +- installazione di Podman e podman-compose - abilitazione dei servizi systemd dichiarati in inventory/group vars -- copia dei dotfiles server e rendering dei template server, incluso il `docker-compose.yml` dello stack servizi -- attivazione di firewalld con servizio SSH esplicitamente abilitato +- copia dei dotfiles server e rendering dei template server, incluso il `docker-compose.yml` dello stack servizi e dell'unit `podman-compose-server` (attivazione manuale) +- attivazione di firewalld con SSH, Cockpit (`9090/tcp`), HTTP e HTTPS abilitati - Syncthing escluso dal profilo server Rocky +Nginx Proxy Manager pubblica solo `80/tcp` e `443/tcp`; la sua interfaccia di amministrazione e +associata a `127.0.0.1:81` ed e raggiungibile da Ikaros o Nymph con l'alias Bash `npm-tunnel`. +Nextcloud resta disabilitato e il profilo non crea directory `/srv/nextcloud`. + ### DuckDNS `profile_server` genera `~/duckdns/duck.sh` con permessi `0700`, mantenendo il percorso dello @@ -450,7 +454,7 @@ ansible-playbook ansible/site.yml --limit --tags , --check -- ansible-playbook ansible/site.yml --limit --start-at-task "" --check --diff ansible-lint ansible/roles/ yamllint ansible/path/to/file.yml -docker compose -f /opt/docker/server/docker-compose.yml config +podman-compose -f /opt/docker/server/docker-compose.yml config ``` ## Tag supportati dal playbook diff --git a/README.md b/README.md index 57cb6a0..8fe62a9 100644 --- a/README.md +++ b/README.md @@ -104,11 +104,16 @@ That gives it Fedora packages through DNF, Docker from the official repository, dotfiles and templates. The profile provisions configuration only: it does not transfer data, start the Compose stack, update DNS, or perform a cutover. -The server profile installs platform-specific packages, Docker CE from the official repository, -declared systemd services, the server Compose stack, and firewalld. The Rocky server excludes +The server profile installs platform-specific packages, Podman and podman-compose, +declared systemd services, the server Compose stack behind the `podman-compose-server` systemd unit, and firewalld. The Rocky server excludes Syncthing. Rocky bind mounts use private SELinux relabeling for application data while host system files remain unchanged. +Firewalld enables SSH, Cockpit (`9090/tcp`), HTTP and HTTPS. Nginx Proxy Manager publishes only +`80/tcp` and `443/tcp`; its administration interface is bound to `127.0.0.1:81` and can be reached +from Ikaros or Nymph with the `npm-tunnel` Bash alias. Nextcloud remains disabled and the profile +does not provision any `/srv/nextcloud` directories. + Server identity comes from `server_username`, `server_user_group`, and `server_user_home` in `ansible/inventory/group_vars/server.yml`. `server_username` defaults to `username`, but it can be overridden, for example: ```bash @@ -378,7 +383,7 @@ ansible-playbook ansible/site.yml --limit --tags , --check -- ansible-playbook ansible/site.yml --limit --start-at-task "" --check --diff ansible-lint ansible/roles/ yamllint ansible/path/to/file.yml -docker compose -f /opt/docker/server/docker-compose.yml config +podman-compose -f /opt/docker/server/docker-compose.yml config ``` ## Tags diff --git a/ansible/inventory/group_vars/platform_rocky.yml b/ansible/inventory/group_vars/platform_rocky.yml index 49ef00a..3d4e6bf 100644 --- a/ansible/inventory/group_vars/platform_rocky.yml +++ b/ansible/inventory/group_vars/platform_rocky.yml @@ -18,11 +18,9 @@ rocky_syncthing_archive_url: >- rocky_manage_openzfs_repo: false rocky_manage_syncthing_binary: false -rocky_manage_docker_repo: false +rocky_manage_podman: false rocky_manage_github_cli_repo: false -rocky_docker_repo_url: https://download.docker.com/linux/rhel/docker-ce.repo -rocky_docker_repo_file: /etc/yum.repos.d/docker-ce.repo rocky_github_cli_repo_url: https://cli.github.com/packages/rpm/gh-cli.repo rocky_github_cli_repo_file: /etc/yum.repos.d/gh-cli.repo @@ -47,8 +45,8 @@ rocky_packages_base: - firewalld - openssh-server - rsync + - selinux-policy-targeted - sudo rocky_profile_packages: [] -rocky_docker_packages: [] -rocky_docker_conflicting_packages: [] +rocky_podman_packages: [] diff --git a/ansible/inventory/group_vars/rocky_server.yml b/ansible/inventory/group_vars/rocky_server.yml index 2d7715d..0713092 100644 --- a/ansible/inventory/group_vars/rocky_server.yml +++ b/ansible/inventory/group_vars/rocky_server.yml @@ -1,5 +1,5 @@ --- -rocky_manage_docker_repo: true +rocky_manage_podman: true rocky_manage_github_cli_repo: true rocky_profile_packages: @@ -22,37 +22,22 @@ rocky_profile_packages: - ranger - ripgrep -rocky_docker_packages: - - containerd.io - - docker-buildx-plugin - - docker-ce - - docker-ce-cli - - docker-compose-plugin - -rocky_docker_conflicting_packages: - - docker - - docker-client - - docker-client-latest - - docker-common - - docker-engine - - docker-latest - - docker-latest-logrotate - - docker-logrotate - - runc +rocky_podman_packages: + - podman + - podman-compose enabled_services: - firewalld - - docker + - podman.socket server_firewall_backend: firewalld server_firewalld_zone: public server_firewalld_services: - ssh + - cockpit + - http + - https server_firewalld_ports: [] -server_firewalld_absent_ports: - - 22000/tcp - - 22000/udp - - 21027/udp server_sshd_service_name: sshd server_compose_selinux_mount_option: Z server_syncthing_enabled: false diff --git a/ansible/inventory/group_vars/server.yml b/ansible/inventory/group_vars/server.yml index e947249..1456571 100644 --- a/ansible/inventory/group_vars/server.yml +++ b/ansible/inventory/group_vars/server.yml @@ -86,14 +86,6 @@ server_directories: owner: root group: root mode: "0755" - - path: /srv/nextcloud - owner: root - group: root - mode: "0755" - - path: /srv/nextcloud/data - owner: root - group: root - mode: "0755" server_syncthing_enabled: true server_syncthing_directories: diff --git a/ansible/roles/packages_rocky/tasks/main.yml b/ansible/roles/packages_rocky/tasks/main.yml index 4bfa28d..fb4c016 100644 --- a/ansible/roles/packages_rocky/tasks/main.yml +++ b/ansible/roles/packages_rocky/tasks/main.yml @@ -50,16 +50,6 @@ state: enabled when: rocky_manage_openzfs_repo | bool -- name: Configure official Docker RPM repository - tags: [packages, docker] - ansible.builtin.get_url: - url: "{{ rocky_docker_repo_url }}" - dest: "{{ rocky_docker_repo_file }}" - owner: root - group: root - mode: "0644" - when: rocky_manage_docker_repo | bool - - name: Configure official GitHub CLI RPM repository tags: [packages] ansible.builtin.get_url: @@ -70,15 +60,6 @@ mode: "0644" when: rocky_manage_github_cli_repo | bool -- name: Remove packages conflicting with Docker CE - tags: [packages, docker] - ansible.builtin.dnf: - name: "{{ rocky_docker_conflicting_packages }}" - state: absent - when: - - rocky_manage_docker_repo | bool - - rocky_docker_conflicting_packages | length > 0 - - name: Refresh Rocky package metadata tags: [packages] ansible.builtin.dnf: @@ -93,19 +74,21 @@ (rocky_common_packages | default([])) + (rocky_packages_base | default([])) + (rocky_profile_packages | default([])) - + (rocky_docker_packages | default([])) + + (rocky_podman_packages | default([])) + (host_packages | default([])) ) | unique }} state: present -- name: Add Rocky user to docker group - tags: [packages, docker] - ansible.builtin.user: - name: "{{ effective_username }}" - groups: docker - append: true - when: rocky_docker_packages | length > 0 +- name: Ensure Podman runtime socket directory exists + tags: [packages, podman] + ansible.builtin.file: + path: /run/podman + state: directory + owner: root + group: root + mode: "0700" + when: rocky_manage_podman | bool - name: Require supported architecture for Syncthing tags: [packages, syncthing] diff --git a/ansible/roles/profile_server/handlers/main.yml b/ansible/roles/profile_server/handlers/main.yml index dd7e309..fd614d2 100644 --- a/ansible/roles/profile_server/handlers/main.yml +++ b/ansible/roles/profile_server/handlers/main.yml @@ -4,3 +4,8 @@ ansible.builtin.service: name: "{{ server_sshd_service_name }}" state: reloaded + +- name: Reload systemd for Podman Compose + tags: [services] + ansible.builtin.systemd: + daemon_reload: true diff --git a/ansible/roles/profile_server/tasks/main.yml b/ansible/roles/profile_server/tasks/main.yml index e5aa68a..f3149aa 100644 --- a/ansible/roles/profile_server/tasks/main.yml +++ b/ansible/roles/profile_server/tasks/main.yml @@ -67,6 +67,10 @@ label: "{{ item.dest }}" no_log: "{{ item.no_log | default(false) }}" +- name: Manage Podman Compose stack + tags: [services, podman] + ansible.builtin.include_tasks: podman-compose.yml + - name: Disable SSH root login on server tags: [services] ansible.builtin.lineinfile: @@ -113,16 +117,3 @@ loop_control: label: "{{ item }}" when: server_firewall_backend == 'firewalld' - -- name: Remove disabled server ports from firewalld - tags: [services, packages] - ansible.posix.firewalld: - port: "{{ item }}" - zone: "{{ server_firewalld_zone }}" - state: disabled - permanent: true - immediate: true - loop: "{{ server_firewalld_absent_ports | default([]) }}" - loop_control: - label: "{{ item }}" - when: server_firewall_backend == 'firewalld' diff --git a/ansible/roles/profile_server/tasks/podman-compose.yml b/ansible/roles/profile_server/tasks/podman-compose.yml new file mode 100644 index 0000000..437bf2f --- /dev/null +++ b/ansible/roles/profile_server/tasks/podman-compose.yml @@ -0,0 +1,10 @@ +--- +- name: Render Podman Compose systemd unit + tags: [services, podman] + ansible.builtin.template: + src: podman-compose-server.service.j2 + dest: /etc/systemd/system/podman-compose-server.service + owner: root + group: root + mode: "0644" + notify: Reload systemd for Podman Compose \ No newline at end of file diff --git a/ansible/roles/profile_server/templates/podman-compose-server.service.j2 b/ansible/roles/profile_server/templates/podman-compose-server.service.j2 new file mode 100644 index 0000000..f7f6fd6 --- /dev/null +++ b/ansible/roles/profile_server/templates/podman-compose-server.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Podman Compose stack for {{ server_username }} +Requires=network-online.target +After=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory={{ server_container_stack_dir }} +ExecStart=/usr/bin/podman-compose up -d +ExecStop=/usr/bin/podman-compose down +ExecReload=/usr/bin/podman-compose up -d + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/ansible/templates/server/docker-compose.yml.j2 b/ansible/templates/server/docker-compose.yml.j2 index d27ed62..f900afc 100644 --- a/ansible/templates/server/docker-compose.yml.j2 +++ b/ansible/templates/server/docker-compose.yml.j2 @@ -1,10 +1,10 @@ --- {% set selinux_volume_option = server_compose_selinux_mount_option | default('') %} -version: "3.8" +name: server services: navidrome: - image: deluan/navidrome:latest + image: docker.io/deluan/navidrome:latest container_name: navidrome restart: unless-stopped expose: @@ -23,19 +23,18 @@ services: depends_on: - navidromedb nginx-proxy-manager: - image: jc21/nginx-proxy-manager:latest + image: docker.io/jc21/nginx-proxy-manager:latest container_name: nginx-proxy-manager restart: unless-stopped ports: - "80:80" - "443:443" - - "81:81" + - "127.0.0.1:81:81" volumes: - "/opt/npm/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}" - "/opt/npm/letsencrypt:/etc/letsencrypt{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}" networks: - web - - gitea # Disabled: prometheus does not have enough resources to run Nextcloud AIO. # nextcloud-aio-mastercontainer: @@ -57,7 +56,7 @@ services: # - web navidromedb: - image: postgres:13 + image: docker.io/library/postgres:13 container_name: navidromedb restart: unless-stopped mem_limit: 2048m @@ -78,7 +77,7 @@ services: - USER_GID=1100 restart: always networks: - - gitea + - web volumes: - /opt/gitea/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }} - /etc/timezone:/etc/timezone:ro @@ -90,7 +89,7 @@ services: {% if server_syncthing_enabled | default(true) | bool %} syncthing: - image: syncthing/syncthing:2 + image: docker.io/syncthing/syncthing:2 container_name: syncthing hostname: syncthing restart: unless-stopped @@ -111,8 +110,6 @@ networks: web: name: server_web external: false - gitea: - external: false # volumes: # nextcloud_aio_mastercontainer: diff --git a/dotfiles/common/.bashrc.aliases b/dotfiles/common/.bashrc.aliases index ddbb6c9..b32737e 100644 --- a/dotfiles/common/.bashrc.aliases +++ b/dotfiles/common/.bashrc.aliases @@ -1,2 +1,5 @@ # Additional Bash aliases. # Keep this file as the extension point for shared aliases. + +# Nginx Proxy Manager administration tunnel on Prometheus. +alias npm-tunnel='ssh -N -o ExitOnForwardFailure=yes -L 8181:127.0.0.1:81 rocky@179.237.102.172'