diff options
23 files changed, 330 insertions, 304 deletions
@@ -4,40 +4,42 @@ Ansible playbook for deploying and managing Podman containers.  -This playbook is for deploying and managing Podman containers in a reproducible way. -By default it will create systemd service files and is compatible with or without the use of pods. +This repo contains two roles, `host` and `containers`, that automate the deployment of Podman containers using quadlet. +Quadlet files and some understanding of quadlet and/or systemd is required to use this tool. ## Usage -- ```ansible-playbook host.yml``` -- ```machinectl shell containers@``` -- ```ansible-galaxy install -r collections/requirements.yml``` -- ```ansible-playbook containers.yml -e @docs/sample-environment/wordpress.yml``` + ansible-playbook host.yml + sudo machinectl shell containers@ + ansible-galaxy install -r collections/requirements.yml + ansible-playbook containers.yml ## Features -- Declare container architecture using Ansible variables file -- Rebuild, stop, start, enable systemd service, disable + remove systemd files -- One command for re-build image, re-generate systemd unit files -- Optionally, use tags for more precise control - - ```container-start```, ```container-stop```, ```generate-systemd```, ```rebuild```, ```remove```, ```service-start```, ```service-stop``` -- Utilizes rootless Podman +- Designed for rootless Podman +- Easily deploy/remove quadlet files and stop/start quadlet services +- Define your application's quadlet files so they are treated as one entity with Ansible ## Sample Environment -A fully working pod with Wordpress and a MariaDB database are in the ```docs/sample-environment``` directory. +A fully working pod with Wordpress and a MariaDB database are in the `docs/sample-environment` directory. +The default variables in the `container` role will use this sample environment for deployment. +Provide your own inventory and/or variables to override this. ## Requirements - Ansible -- Ansible collections - - ```ansible-galaxy install -r collections/requirements.yml``` +- Ansible collections: + - ```ansible-galaxy install -r collections/requirements.yml``` - Podman -- User with ```sudo``` rights - -## Assumptions -- Rootless mode is being used, so tasks are written to use systemd user scope - - Tasks would need to be tweaked for using the root user -- ```containers``` user is automatically created during the ```host.yml``` play -- The tasks were purposely kept simple, its expected that you use Podman runlabels for most options - -## Limitations -- Tasks were written to be run as the unprivileged user - however this is tricky in Ansible - - Because of this, I recommend using ```machinectl shell containers@``` to become user before running the ```containers.yml``` play - - Your milage may vary if you use another method of changing users +- User with `sudo` rights (to create unprivileged user) + +## Operation +- `host.yml` - installs the needed packages and creates the `containers` unprivileged user - use with a privileged account +- `containers.yml` - will copy the quadlet files and start the quadlet - use with the unprivileged account + +## Tags +- `host.yml`: + - `unprivileged-ports` - configures host to allow port `80` and above to be used by unprivileged accounts + - `cpanel-dnsonly` - changes only needed when running on a dnsonly cPanel instance, check `roles/host/tasks/cpanel-dnsonly.yml` for details +- `containers.yml`: + - `create` - create quadlet files + - `remove` - remove quadlet files + - `start` - start quadlet services + - `stop` - stop quadlet services diff --git a/containers.yml b/containers.yml index ab61772..59de80c 100644 --- a/containers.yml +++ b/containers.yml @@ -1,149 +1,5 @@ - hosts: localhost tasks: - - name: Rebuild images - containers.podman.podman_image: - name: "{{ item.name }}:{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}{{ ansible_date_time.second }}" - path: "{{ item.path }}" - build: - file: "{{ item.file }}" - cache: false - tags: rebuild - loop: "{{ containers }}" - - - name: Tag new images to latest - containers.podman.podman_tag: - image: "{{ item.name }}:{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}{{ ansible_date_time.second }}" - target_names: "{{ item.name }}:latest" - tags: rebuild - loop: "{{ containers }}" - - - name: Stop systemd pod service - ansible.builtin.systemd: - name: "pod-{{ pod.name }}.service" - state: stopped - scope: user - ignore_errors: true - tags: - - remove - - service-stop - when: pod is defined - - - name: Remove systemd pod service file - ansible.builtin.file: - path: "~/.config/systemd/user/pod-{{ pod.name }}.service" - state: absent - tags: remove - when: pod is defined - - - name: Stop systemd container service - ansible.builtin.systemd: - name: "container-{{ item.name }}.service" - state: stopped - scope: user - ignore_errors: true - tags: - - remove - - service-stop - loop: "{{ containers }}" - - - name: Remove systemd container service file - ansible.builtin.file: - path: "~/.config/systemd/user/container-{{ item.name }}.service" - state: absent - tags: remove - loop: "{{ containers }}" - - - name: Remove pod - containers.podman.podman_pod: - name: "{{ pod.name }}" - state: absent - tags: - - remove - - container-stop - when: pod is defined - - - name: Remove containers - containers.podman.podman_container: - name: "{{ item.name }}" - state: absent - tags: - - remove - - container-stop - loop: "{{ containers }}" - - - name: Create pod - containers.podman.podman_pod: - name: "{{ pod.name }}" - ports: "{{ pod.ports }}" - network: "{{ pod.network | default(omit) }}" - state: started - tags: container-start - when: pod is defined - - - name: Start containers - ansible.builtin.shell: "podman container runlabel {{ item.runlabel }} {{ item.name}}:latest" - tags: container-start - loop: "{{ containers }}" - - - name: Generate systemd service file for pod - containers.podman.podman_generate_systemd: - name: "{{ pod.name }}" - dest: "~/.config/systemd/user/" - new: true - tags: generate-systemd - when: pod is defined - - - name: Generate systemd service file for container (when pod is not in use) - containers.podman.podman_generate_systemd: - name: "{{ item.name }}" - dest: "~/.config/systemd/user/" - new: true - tags: generate-systemd - loop: "{{ containers }}" - when: pod is not defined - - - name: Reload systemd daemon - ansible.builtin.systemd: - daemon_reload: true - scope: user - tags: - - remove - - generate-systemd - - - name: Pause for container full startup - ansible.builtin.pause: - seconds: 30 - - - name: Remove pod - containers.podman.podman_pod: - name: "{{ pod.name }}" - state: absent - when: pod is defined - - - name: Remove containers - containers.podman.podman_container: - name: "{{ item.name }}" - state: absent - loop: "{{ containers }}" - - - name: Start systemd pod service - ansible.builtin.systemd: - name: "pod-{{ pod.name}}.service" - state: started - enabled: true - scope: user - tags: service-start - when: pod is defined - - - name: Start systemd container service - ansible.builtin.systemd: - name: "container-{{ item.name }}.service" - state: started - enabled: true - scope: user - tags: service-start - loop: "{{ containers }}" - - - name: Prune old images - ansible.builtin.shell: "podman image prune -f" + - ansible.builtin.import_role: + name: "containers" diff --git a/docs/sample-environment/wordpress.yml b/docs/sample-environment/wordpress.yml deleted file mode 100644 index 6f16f9d..0000000 --- a/docs/sample-environment/wordpress.yml +++ /dev/null @@ -1,15 +0,0 @@ -pod: - name: wordpress - ports: - - "8080:80" -# network: - -containers: - - name: wordpress-db - path: "docs/sample-environment/wordpress" - file: "wordpress-db.containerfile" - runlabel: "start" - - name: wordpress-app - path: "docs/sample-environment/wordpress" - file: "wordpress-app.containerfile" - runlabel: "start" diff --git a/docs/sample-environment/wordpress/quadlet/wordpress-app.container b/docs/sample-environment/wordpress/quadlet/wordpress-app.container new file mode 100644 index 0000000..20f9b69 --- /dev/null +++ b/docs/sample-environment/wordpress/quadlet/wordpress-app.container @@ -0,0 +1,13 @@ +[Unit] +Wants=wordpress-pod.service +After=wordpress-pod.service +PartOf=wordpress-pod.service + +[Container] +ContainerName=wordpress-app +Environment=WORDPRESS_DB_HOST=127.0.0.1 WORDPRESS_DB_USER=root WORDPRESS_DB_PASSWORD=TESTTESTTEST WORDPRESS_DB_NAME=wordpress WORDPRESS_TABLE_PREFIX=wp_ +Image=docker.io/library/wordpress:latest +PodmanArgs=--pod wordpress + +[Install] +WantedBy=default.target diff --git a/docs/sample-environment/wordpress/quadlet/wordpress-db.container b/docs/sample-environment/wordpress/quadlet/wordpress-db.container new file mode 100644 index 0000000..8e6e0d6 --- /dev/null +++ b/docs/sample-environment/wordpress/quadlet/wordpress-db.container @@ -0,0 +1,13 @@ +[Unit] +Wants=wordpress-pod.service +After=wordpress-pod.service +PartOf=wordpress-pod.service + +[Container] +ContainerName=wordpress-db +Environment=MARIADB_DATABASE=wordpress MARIADB_ROOT_PASSWORD=TESTTESTTEST +Image=docker.io/mariadb:latest +PodmanArgs=--pod wordpress + +[Install] +WantedBy=default.target diff --git a/docs/sample-environment/wordpress/quadlet/wordpress.pod b/docs/sample-environment/wordpress/quadlet/wordpress.pod new file mode 100644 index 0000000..eea748a --- /dev/null +++ b/docs/sample-environment/wordpress/quadlet/wordpress.pod @@ -0,0 +1,11 @@ +[Unit] +Wants=check-network-online.service wordpress-app.service wordpress-db.service +Before=wordpress-app.service wordpress-db.service +After=check-network-online.service + +[Pod] +PublishPort=8080:80 +PodName=wordpress + +[Install] +WantedBy=default.target @@ -1,120 +1,6 @@ - hosts: localhost become: true - vars: - shell_service_status_helper: | - echo "----systemd----" - systemctl --user list-units 'pod-*' -q - echo "" - systemctl --user list-units 'container-*' -q - echo "" - echo "----podman----" - podman pod list --sort status --format={{ '"{{.Status}} {{.Name}}"' }} - echo "" - podman container list --all --sort status --format={{ '"{{.State}} {{.Status}} {{.Names}}"' }} - echo "" tasks: - - name: Create containers user - ansible.builtin.user: - name: "containers" - - - name: Add bashrc for container service status on login - ansible.builtin.blockinfile: - path: "/home/containers/.bashrc" - owner: "containers" - group: "containers" - create: true - block: "{{ shell_service_status_helper }}" - - - name: Check if fish shell is installed - ansible.builtin.stat: - path: "/usr/bin/fish" - register: fish - - - name: Add fish config for container service status on login - ansible.builtin.blockinfile: - path: "/home/containers/.config/fish/conf.d/containers.fish" - owner: "containers" - group: "containers" - create: true - block: "{{ shell_service_status_helper }}" - when: fish.stat.exists - - - name: Fix permissions on /home/containers - ansible.builtin.file: - path: "/home/containers" - state: directory - owner: "containers" - group: "containers" - recurse: true - - - name: Install systemd-container and podman - ansible.builtin.package: - name: - - "systemd-container" - - "podman" - state: present - - - name: Confirm systemd-linger is set for containers user - ansible.builtin.stat: - path: "/var/lib/systemd/linger/containers" - register: linger - - - name: Set systemd-linger for containers user (if necessary) - ansible.builtin.shell: "loginctl enable-linger containers" - when: not linger.stat.exists - - - name: Unprivileged port block - block: - - name: Confirm port 80 and above is allowed for unprivileged use - ansible.builtin.shell: "sysctl net.ipv4.ip_unprivileged_port_start |grep 80" - - rescue: - - name: Set sysctl parameter net.ipv4.ip_unprivileged_port_start=80 - ansible.builtin.lineinfile: - path: "/etc/sysctl.conf" - regexp: "^net.ipv4.ip_unprivileged_port_start=80" - line: "net.ipv4.ip_unprivileged_port_start=80" - - - name: Reload sysctl - ansible.builtin.shell: "sysctl -p /etc/sysctl.conf" - - - name: Confirm port 80 and above is allowed for unprivileged use - ansible.builtin.shell: "sysctl net.ipv4.ip_unprivileged_port_start |grep 80" - tags: - - never - - unprivileged-ports - - - name: cPanel DNS-only block - block: - - name: Confirm if cpsrvd is not listening on http ports - ansible.builtin.shell: "whmapi1 get_tweaksetting key='disable_cphttpd' |grep 'value: 1' || /bin/true" - register: cpsrv_listen - - - name: Turn off cpsrvd listening on http ports (if necessary) - ansible.builtin.shell: "whmapi1 set_tweaksetting key='disable_cphttpd' value='1' ; /scripts/restartsrv_cpsrvd" - when: cpsrv_listen.stdout | length == 0 - - - name: Turn off firewalld - ansible.builtin.service: - name: "firewalld" - state: stopped - enabled: false - - - name: Create new tmp directory for podman - ansible.builtin.file: - path: "/var/containers/tmp" - owner: containers - group: containers - state: directory - - - name: Configure podman to use new tmp directory - ansible.builtin.blockinfile: - path: "/etc/containers/containers.conf" - create: true - block: | - [engine] - env = ["TMPDIR=/var/containers/tmp"] - tags: - - never - - cpanel-dnsonly + - ansible.builtin.import_role: + name: "host" diff --git a/roles/containers/defaults/main.yml b/roles/containers/defaults/main.yml new file mode 100644 index 0000000..ade45f3 --- /dev/null +++ b/roles/containers/defaults/main.yml @@ -0,0 +1,11 @@ +quadlet_path: "../../docs/sample-environment/wordpress/quadlet" + +quadlets: + - name: "wordpress-pod" + file: "wordpress.pod" + + - name: "wordpress-app" + file: "wordpress-app.container" + + - name: "wordpress-db" + file: "wordpress-db.container" diff --git a/roles/containers/tasks/main.yml b/roles/containers/tasks/main.yml new file mode 100644 index 0000000..02ee577 --- /dev/null +++ b/roles/containers/tasks/main.yml @@ -0,0 +1,17 @@ +- ansible.builtin.import_tasks: quadlet_create.yml + tags: + - create + +- ansible.builtin.import_tasks: quadlet_start.yml + tags: + - start + +- ansible.builtin.import_tasks: quadlet_stop.yml + tags: + - never + - stop + +- ansible.builtin.import_tasks: quadlet_remove.yml + tags: + - never + - remove diff --git a/roles/containers/tasks/quadlet_create.yml b/roles/containers/tasks/quadlet_create.yml new file mode 100644 index 0000000..ffbae8a --- /dev/null +++ b/roles/containers/tasks/quadlet_create.yml @@ -0,0 +1,22 @@ +- name: Create quadlet directory + ansible.builtin.file: + path: "{{ lookup('env', 'HOME') }}/.config/containers/systemd" + state: "directory" + +- name: Copy quadlet files into quadlet directory + ansible.builtin.copy: + src: "{{ quadlet_path}}/{{ item.file }}" + dest: "{{ lookup('env', 'HOME') }}/.config/containers/systemd/{{ item.file }}" + loop_control: + label: "{{ item.name }} -> {{ item.file }}" + loop: "{{ quadlets }}" + register: quadlet_files + +- name: Reload systemd daemon + ansible.builtin.systemd: + daemon_reload: true + scope: "user" + when: quadlet_files.changed + +- name: Check quadlet status + ansible.builtin.shell: "/usr/lib/systemd/system-generators/podman-system-generator --user --dryrun" diff --git a/roles/containers/tasks/quadlet_remove.yml b/roles/containers/tasks/quadlet_remove.yml new file mode 100644 index 0000000..e6bc05b --- /dev/null +++ b/roles/containers/tasks/quadlet_remove.yml @@ -0,0 +1,14 @@ +- name: Remove quadlet files from quadlet directory + ansible.builtin.file: + path: "{{ lookup('env', 'HOME') }}/.config/containers/systemd/{{ item.file }}" + state: "absent" + loop_control: + label: "{{ item.name }} -> {{ item.file }}" + loop: "{{ quadlets }}" + register: quadlet_files + +- name: Reload systemd daemon + ansible.builtin.systemd: + daemon_reload: true + scope: "user" + when: quadlet_files.changed diff --git a/roles/containers/tasks/quadlet_start.yml b/roles/containers/tasks/quadlet_start.yml new file mode 100644 index 0000000..5dcd39a --- /dev/null +++ b/roles/containers/tasks/quadlet_start.yml @@ -0,0 +1,27 @@ +- name: Start quadlet + ansible.builtin.systemd_service: + name: "{{ item.name }}" + state: "started" + scope: "user" + loop_control: + label: "{{ item.name}}.service" + loop: "{{ quadlets }}" + +- name: Check for quadlet not in active or activating state + ansible.builtin.shell: "systemctl --user is-active {{ item.name }}.service" + loop_control: + label: "{{ item.name}}.service: {{ quadlet_status.stdout }}" + loop: "{{ quadlets }}" + register: quadlet_status + failed_when: quadlet_status.stdout not in ['active', 'activating'] + + +- name: Wait for quadlet state to go active + ansible.builtin.shell: "systemctl --user is-active {{ item.name }}.service" + loop_control: + label: "{{ item.name}}.service: {{ quadlet_status.stdout }}" + loop: "{{ quadlets }}" + register: quadlet_status + until: quadlet_status.stdout == 'active' + delay: 2 + retries: 25 diff --git a/roles/containers/tasks/quadlet_stop.yml b/roles/containers/tasks/quadlet_stop.yml new file mode 100644 index 0000000..b8a83f3 --- /dev/null +++ b/roles/containers/tasks/quadlet_stop.yml @@ -0,0 +1,8 @@ +- name: Stop quadlet + ansible.builtin.systemd_service: + name: "{{ item.name }}" + state: "stopped" + scope: "user" + loop_control: + label: "{{ item.name}}.service" + loop: "{{ quadlets }}" diff --git a/roles/host/defaults/main.yml b/roles/host/defaults/main.yml new file mode 100644 index 0000000..c393dc8 --- /dev/null +++ b/roles/host/defaults/main.yml @@ -0,0 +1,9 @@ +host_shell_login_helper: | + echo "----pods----" + podman pod list --sort status --format={{ '"{{.Status}} {{.Name}}"' }} + echo "" + echo "----containers----" + podman container list --all --sort status --format={{ '"{{.State}} {{.Status}} {{.Names}}"' }} + echo "" + +host_containers_user: "containers" diff --git a/roles/host/files/check-network-online.service b/roles/host/files/check-network-online.service new file mode 100644 index 0000000..afadbfe --- /dev/null +++ b/roles/host/files/check-network-online.service @@ -0,0 +1,14 @@ +#This is needed because user units cannot check or interact with system units such as network-online.target +#https://github.com/containers/podman/issues/22197 +#https://github.com/systemd/systemd/issues/3312 + +[Unit] +Description=Check for system level network-online.target (for users) + +[Service] +Type=oneshot +ExecStart=bash -c 'until systemctl is-active network-online.target; do sleep 1; done' +RemainAfterExit=yes + +[Install] +WantedBy=default.target diff --git a/roles/host/tasks/cpanel-dnsonly.yml b/roles/host/tasks/cpanel-dnsonly.yml new file mode 100644 index 0000000..dbb9062 --- /dev/null +++ b/roles/host/tasks/cpanel-dnsonly.yml @@ -0,0 +1,28 @@ +- name: Confirm if cpsrvd is not listening on http ports + ansible.builtin.shell: "whmapi1 get_tweaksetting key='disable_cphttpd' |grep 'value: 1' || /bin/true" + register: cpsrv_listen + +- name: Turn off cpsrvd listening on http ports (if necessary) + ansible.builtin.shell: "whmapi1 set_tweaksetting key='disable_cphttpd' value='1' ; /scripts/restartsrv_cpsrvd" + when: cpsrv_listen.stdout | length == 0 + +- name: Turn off firewalld + ansible.builtin.service: + name: "firewalld" + state: stopped + enabled: false + +- name: Create new tmp directory for podman + ansible.builtin.file: + path: "/var/containers/tmp" + owner: "{{ host_containers_user }}" + group: "{{ host_containers_user }}" + state: directory + +- name: Configure podman to use new tmp directory + ansible.builtin.blockinfile: + path: "/etc/containers/containers.conf" + create: true + block: | + [engine] + env = ["TMPDIR=/var/containers/tmp"] diff --git a/roles/host/tasks/linger.yml b/roles/host/tasks/linger.yml new file mode 100644 index 0000000..dffc6a7 --- /dev/null +++ b/roles/host/tasks/linger.yml @@ -0,0 +1,8 @@ +- name: Confirm systemd-linger is set for containers user + ansible.builtin.stat: + path: "/var/lib/systemd/linger/{{ host_containers_user }}" + register: linger + +- name: Set systemd-linger for containers user (if necessary) + ansible.builtin.shell: "loginctl enable-linger {{ host_containers_user }}" + when: not linger.stat.exists diff --git a/roles/host/tasks/main.yml b/roles/host/tasks/main.yml new file mode 100644 index 0000000..5b9dd6b --- /dev/null +++ b/roles/host/tasks/main.yml @@ -0,0 +1,19 @@ +- ansible.builtin.import_tasks: packages.yml + +- ansible.builtin.import_tasks: user.yml + +- ansible.builtin.import_tasks: linger.yml + +- ansible.builtin.import_tasks: shell-helper.yml + +- ansible.builtin.import_tasks: systemd-user-network-check.yml + +- ansible.builtin.import_tasks: unprivileged-ports.yml + tags: + - never + - unprivileged-ports + +- ansible.builtin.import_tasks: cpanel-dnsonly.yml + tags: + - never + - cpanel-dnsonly diff --git a/roles/host/tasks/packages.yml b/roles/host/tasks/packages.yml new file mode 100644 index 0000000..df78985 --- /dev/null +++ b/roles/host/tasks/packages.yml @@ -0,0 +1,6 @@ +- name: Install systemd-container and podman + ansible.builtin.package: + name: + - "systemd-container" + - "podman" + state: present diff --git a/roles/host/tasks/shell-helper.yml b/roles/host/tasks/shell-helper.yml new file mode 100644 index 0000000..e36784a --- /dev/null +++ b/roles/host/tasks/shell-helper.yml @@ -0,0 +1,31 @@ +- name: Add bashrc for container service status on login + ansible.builtin.blockinfile: + path: "/home/{{ host_containers_user }}/.bashrc" + owner: "{{ host_containers_user }}" + group: "{{ host_containers_user }}" + create: true + block: "{{ host_shell_login_helper }}" + +- name: Check if fish shell is installed + ansible.builtin.stat: + path: "/usr/bin/fish" + register: fish + +- name: Block for fish + block: + - name: Create fish config directory + ansible.builtin.file: + path: "/home/{{ host_containers_user }}/.config/fish/conf.d" + state: directory + owner: "{{ host_containers_user }}" + group: "{{ host_containers_user }}" + + - name: Add fish config for container service status on login + ansible.builtin.blockinfile: + path: "/home/{{ host_containers_user }}/.config/fish/conf.d/containers.fish" + owner: "{{ host_containers_user }}" + group: "{{ host_containers_user }}" + create: true + block: "{{ host_shell_login_helper }}" + when: fish.stat.exists + when: fish.stat.exists diff --git a/roles/host/tasks/systemd-user-network-check.yml b/roles/host/tasks/systemd-user-network-check.yml new file mode 100644 index 0000000..4c87f82 --- /dev/null +++ b/roles/host/tasks/systemd-user-network-check.yml @@ -0,0 +1,20 @@ +#This is a workaround so we can check for the network to come up before starting the quadlets +#https://github.com/containers/podman/issues/22197 +#https://github.com/systemd/systemd/issues/3312 + +- name: Copy check-network-online.service into systemd user service directory + ansible.builtin.copy: + src: "check-network-online.service" + dest: "/etc/systemd/user/check-network-online.service" + register: systemd + +- name: Reload systemd daemon + ansible.builtin.systemd_service: + daemon_reload: true + when: systemd.changed + +- name: Enable check-network-online.service for all users + ansible.builtin.systemd_service: + name: "check-network-online.service" + enabled: true + scope: "global" diff --git a/roles/host/tasks/unprivileged-ports.yml b/roles/host/tasks/unprivileged-ports.yml new file mode 100644 index 0000000..003646a --- /dev/null +++ b/roles/host/tasks/unprivileged-ports.yml @@ -0,0 +1,17 @@ +- name: Unprivileged port block + block: + - name: Confirm port 80 and above is allowed for unprivileged use + ansible.builtin.shell: "sysctl net.ipv4.ip_unprivileged_port_start |grep 80" + + rescue: + - name: Set sysctl parameter net.ipv4.ip_unprivileged_port_start=80 + ansible.builtin.lineinfile: + path: "/etc/sysctl.conf" + regexp: "^net.ipv4.ip_unprivileged_port_start=80" + line: "net.ipv4.ip_unprivileged_port_start=80" + + - name: Reload sysctl + ansible.builtin.shell: "sysctl -p /etc/sysctl.conf" + + - name: Confirm port 80 and above is allowed for unprivileged use + ansible.builtin.shell: "sysctl net.ipv4.ip_unprivileged_port_start |grep 80" diff --git a/roles/host/tasks/user.yml b/roles/host/tasks/user.yml new file mode 100644 index 0000000..40e9f4c --- /dev/null +++ b/roles/host/tasks/user.yml @@ -0,0 +1,9 @@ +- name: Create containers user + ansible.builtin.user: + name: "{{ host_containers_user }}" + +- name: Add containers user to systemd-journal group + ansible.builtin.user: + name: "{{ host_containers_user }}" + groups: "systemd-journal" + append: true |
