diff --git a/roles/service/defaults/main.yaml b/roles/service/defaults/main.yaml index 9963233..be20b2b 100644 --- a/roles/service/defaults/main.yaml +++ b/roles/service/defaults/main.yaml @@ -17,6 +17,7 @@ service_container_devices: [] service_container_secrets: [] service_container_env: {} service_container_add_capabilities: [] +service_container_pinp: false service_database_type: none service_database_additional_networks: [] diff --git a/roles/service/meta/argument_specs.yaml b/roles/service/meta/argument_specs.yaml index 7f96c26..5ddd7c0 100644 --- a/roles/service/meta/argument_specs.yaml +++ b/roles/service/meta/argument_specs.yaml @@ -277,6 +277,22 @@ argument_specs: default: [] elements: str + service_container_pinp: + description: + - If true, runs the container with podman in podman + - This starts a podman service inside the outer container + - The podman socket is exposed to the inner container at /var/run/docker.sock + - >- + This allows the container to manage other containers, which are run inside the + same outer container + - >- + The inner containers use host networking, so they share the network namespace + with the outer container and each other. + - This support is experimental and may not work with all images or configurations. + type: bool + required: false + default: false + service_database_type: description: - Database type to set up. @@ -571,6 +587,21 @@ argument_specs: the name of the environment variable. Defaults to secret name. type: str required: false + pinp: + description: + - If true, runs the container with podman in podman + - This starts a podman service inside the outer container + - The podman socket is exposed to the inner container at /var/run/docker.sock + - >- + This allows the container to manage other containers, which are run inside the + same outer container + - >- + The inner containers use host networking, so they share the network namespace + with the outer container and each other. + - This support is experimental and may not work with all images or configurations. + type: bool + required: false + default: false service_requires: description: List of systemd units this service container depends on. diff --git a/roles/service/tasks/additional.yaml b/roles/service/tasks/additional.yaml index eff14b5..ea0b674 100644 --- a/roles/service/tasks/additional.yaml +++ b/roles/service/tasks/additional.yaml @@ -4,17 +4,17 @@ name: container vars: container_name: "{{ _service_additional_container.name }}" - container_image: "{{ _service_additional_container.image }}" - container_command: "{{ _service_additional_container.command }}" - container_entrypoint: "{{ _service_additional_container.entrypoint }}" - container_user: "{{ _service_additional_container.user }}" - container_mounts: "{{ _service_additional_container_mounts }}" + container_image: "{{ _service_additional_container_final.image }}" + container_entrypoint: "{{ _service_additional_container_final.entrypoint }}" + container_command: "{{ _service_additional_container_final.command }}" + container_user: "{{ _service_additional_container_final.user }}" + container_mounts: "{{ _service_additional_container_final.mounts }}" container_devices: "{{ _service_additional_container.devices }}" container_publish_ports: "{{ _service_additional_container_publish_ports }}" container_networks: "{{ _service_additional_container_networks }}" container_hostname: "{{ _service_additional_container.name | regex_replace('^' ~ service_name ~ '-', '') }}" container_secrets: "{{ _service_additional_container_secrets }}" - container_env: "{{ _service_additional_container.env }}" + container_env: "{{ _service_additional_container_final.env }}" container_add_capabilities: "{{ _service_additional_container.add_capabilities }}" container_requires: "{{ _service_container_requires }}" container_wants: "{{ _service_additional_container_wants }}" diff --git a/roles/service/tasks/host_mounts.yaml b/roles/service/tasks/host_mounts.yaml index 28d9bf8..5a46f18 100644 --- a/roles/service/tasks/host_mounts.yaml +++ b/roles/service/tasks/host_mounts.yaml @@ -34,3 +34,28 @@ directory_mode: "0755" notify: Restart container service {{ service_name }} loop: "{{ _service_all_copy_mounts | zip(_service_all_copy_mount_host_files) }}" + +- name: Template entrypoint for pinp + ansible.builtin.template: + src: "pinp-entrypoint.sh.j2" + dest: "{{ _service_host_directory }}/mounts/pinp-entrypoint.sh" + mode: "0755" + vars: + pinp_inner_name: "{{ service_name }}" + pinp_inner_image: "{{ service_container_image }}" + pinp_inner_mounts: "{{ _service_container_pinp_inner_mounts }}" + pinp_inner_env: "{{ service_container_env }}" + when: service_container_pinp +- name: Template entrypoint for pinp of additional containers + ansible.builtin.template: + src: "pinp-entrypoint.sh.j2" + dest: "{{ _service_host_directory }}/mounts/{{ _service_additional_container.name }}-pinp-entrypoint.sh" + mode: "0755" + loop: "{{ _service_additional_containers | selectattr('pinp') }}" + loop_control: + loop_var: _service_additional_container + vars: + pinp_inner_name: "{{ _service_additional_container.name }}" + pinp_inner_image: "{{ _service_additional_container.image }}" + pinp_inner_mounts: "{{ _service_additional_container_pinp_inner_mounts }}" + pinp_inner_env: "{{ _service_additional_container.env }}" diff --git a/roles/service/tasks/main.yaml b/roles/service/tasks/main.yaml index 23cd41e..9498609 100644 --- a/roles/service/tasks/main.yaml +++ b/roles/service/tasks/main.yaml @@ -14,9 +14,12 @@ ansible.builtin.include_tasks: secrets.yaml when: _service_container_secrets | length > 0 -- name: Template mounts for {{ service_name }} +- name: Host mounts for {{ service_name }} ansible.builtin.include_tasks: host_mounts.yaml - when: (_service_all_template_mounts + _service_all_copy_mounts) | length > 0 + when: >- + (_service_all_template_mounts + _service_all_copy_mounts) | length > 0 + or service_container_pinp + or (_service_additional_containers | selectattr('pinp') | length > 0) - name: Additional containers for {{ service_name }} ansible.builtin.include_tasks: additional.yaml @@ -36,16 +39,16 @@ name: container vars: container_name: "{{ service_name }}" - container_image: "{{ service_container_image }}" - container_command: "{{ service_container_command }}" - container_entrypoint: "{{ service_container_entrypoint }}" - container_user: "{{ service_container_user }}" - container_mounts: "{{ _service_container_mounts }}" + container_image: "{{ _service_container.image }}" + container_entrypoint: "{{ _service_container.entrypoint }}" + container_command: "{{ _service_container.command }}" + container_user: "{{ _service_container.user }}" + container_mounts: "{{ _service_container.mounts }}" container_devices: "{{ service_container_devices }}" container_publish_ports: "{{ _service_container_publish_ports }}" container_networks: "{{ _service_container_networks }}" container_secrets: "{{ _service_container_secrets }}" - container_env: "{{ service_container_env }}" + container_env: "{{ _service_container.env }}" container_add_capabilities: "{{ service_container_add_capabilities }}" container_requires: "{{ _service_container_requires }}" container_wants: "{{ _service_container_wants }}" diff --git a/roles/service/templates/pinp-entrypoint.sh.j2 b/roles/service/templates/pinp-entrypoint.sh.j2 new file mode 100644 index 0000000..fbe1642 --- /dev/null +++ b/roles/service/templates/pinp-entrypoint.sh.j2 @@ -0,0 +1,26 @@ +#!/bin/bash +# {{ ansible_managed }} +_term() { + echo "Received SIGTERM, stopping all containers" + kill "$child" +} + +podman system service -t 0 & + +podman run \ + --rm \ + -v /run/secrets:/run/secrets:ro \ +{% for key, value in pinp_inner_env.items() %} + -e {{ key }}={{ value }} \ +{% endfor %} + -v /tmp/storage-run-1000/podman/podman.sock:/var/run/docker.sock \ +{% for mount in pinp_inner_mounts %} + --mount type={{ mount.type }},source={{ mount.source }},destination={{ mount.destination }}{% if mount.readonly | default(false) %},readonly{% endif %} \ +{% endfor %} + --name {{ pinp_inner_name }} \ + --network host \ + {{ pinp_inner_image }} & + +child=$! +trap _term SIGTERM +wait "$!" diff --git a/roles/service/vars/main/additional.yaml b/roles/service/vars/main/additional.yaml index bc63e55..dd4a083 100644 --- a/roles/service/vars/main/additional.yaml +++ b/roles/service/vars/main/additional.yaml @@ -13,6 +13,7 @@ _service_additional_container_same_image_defaults: devices: "{{ service_container_devices }}" env: "{{ service_container_env }}" add_capabilities: "{{ service_container_add_capabilities }}" + pinp: false _service_additional_container_different_image_defaults: user: "" @@ -24,6 +25,7 @@ _service_additional_container_different_image_defaults: env: {} add_capabilities: [] secrets: [] + pinp: false _service_additional_same_image_containers: >- {{ @@ -204,3 +206,59 @@ _service_additional_container_mounts: >- else _service_container_mounts }} + + +_service_additional_plain_container: + image: "{{ _service_additional_container.image }}" + entrypoint: "{{ _service_additional_container.entrypoint }}" + command: "{{ _service_additional_container.command }}" + user: "{{ _service_additional_container.user }}" + env: "{{ _service_additional_container.env }}" + mounts: "{{ _service_additional_container_mounts }}" + +_service_additional_pinp_container_mounts: + - type: bind + source: "{{ _service_host_directory }}/mounts/{{ _service_additional_container.name }}-entrypoint.sh" + destination: /entrypoint.sh + readonly: true + - type: volume + source: "{{ _service_additional_container.name }}-containers" + destination: /home/podman/.local/share/containers + +_service_additional_pinp_container: + image: quay.io/podman/stable:latest + entrypoint: /entrypoint.sh + command: [] + user: podman + env: {} + mounts: >- + {{ + _service_additional_pinp_container_mounts + + ( + _service_additional_container_mounts + | zip( + _service_additional_container_mounts + | map(attribute='source') + | map('replace', '/', '_') + | map('regex_replace', '^', '/mounts/') + | map('community.general.dict_kv', 'destination') + ) + | map('combine') + ) + }} + +_service_additional_container_final: >- + {{ _service_additional_pinp_container if _service_additional_container.pinp else _service_additional_plain_container }} + +_service_additional_container_pinp_inner_mounts: >- + {{ + _service_additional_container_mounts + | zip( + _service_additional_container_mounts + | map(attribute='source') + | map('replace', '/', '_') + | map('regex_replace', '^', '/mounts/') + | map('community.general.dict_kv', 'source') + ) + | map('combine') + }} diff --git a/roles/service/vars/main/pinp.yaml b/roles/service/vars/main/pinp.yaml new file mode 100644 index 0000000..4934c32 --- /dev/null +++ b/roles/service/vars/main/pinp.yaml @@ -0,0 +1,55 @@ +--- +_service_plain_container: + image: "{{ service_container_image }}" + entrypoint: "{{ service_container_entrypoint }}" + command: "{{ service_container_command }}" + user: "{{ service_container_user }}" + env: "{{ service_container_env }}" + mounts: "{{ _service_container_mounts }}" + +_service_pinp_container_mounts: + - type: bind + source: "{{ _service_host_directory }}/mounts/entrypoint.sh" + destination: /entrypoint.sh + readonly: true + - type: volume + source: "containers" + destination: /home/podman/.local/share/containers + +_service_pinp_container: + image: quay.io/podman/stable:latest + entrypoint: /entrypoint.sh + command: [] + user: podman + env: {} + mounts: >- + {{ + _service_pinp_container_mounts + + ( + _service_container_mounts + | zip( + _service_container_mounts + | map(attribute='source') + | map('replace', '/', '_') + | map('regex_replace', '^', '/mounts/') + | map('community.general.dict_kv', 'destination') + ) + | map('combine') + ) + }} + +_service_container: >- + {{ _service_pinp_container if service_container_pinp else _service_plain_container }} + +_service_container_pinp_inner_mounts: >- + {{ + _service_container_mounts + | zip( + _service_container_mounts + | map(attribute='source') + | map('replace', '/', '_') + | map('regex_replace', '^', '/mounts/') + | map('community.general.dict_kv', 'source') + ) + | map('combine') + }} diff --git a/roles/windmill/tasks/main.yaml b/roles/windmill/tasks/main.yaml index d3e458f..e0bce92 100644 --- a/roles/windmill/tasks/main.yaml +++ b/roles/windmill/tasks/main.yaml @@ -18,25 +18,21 @@ MODE: server service_additional_containers: - name: worker - image: quay.io/podman/stable:latest - user: podman - entrypoint: /entrypoint.sh + pinp: true mounts: - type: volume source: worker-logs - destination: /worker-logs + destination: /tmp/windmill/logs - type: volume source: worker-dependency-cache - destination: /worker-dependency-cache - - type: template - source: worker_entrypoint.sh.j2 - destination: /entrypoint.sh - mode: "0755" - - type: volume - source: worker-containers - destination: /home/podman/.local/share/containers - publish_ports: [] - env: {} + destination: /tmp/windmill/cache + env: + DATABASE_URL_FILE: /run/secrets/postgres-url + MODE: worker + WORKER_GROUP: default + ENABLE_UNSHARE_PID: "true" + UNSHARE_ISOLATION_FLAGS: "--user --map-root-user --pid --fork" + - name: worker-native env: DATABASE_URL_FILE: /run/secrets/postgres-url diff --git a/roles/windmill/templates/worker_entrypoint.sh.j2 b/roles/windmill/templates/worker_entrypoint.sh.j2 deleted file mode 100644 index 3bd2279..0000000 --- a/roles/windmill/templates/worker_entrypoint.sh.j2 +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# {{ ansible_managed }} -_term() { - echo "Received SIGTERM, stopping all containers" - kill "$child" -} - -podman system service -t 0 & - -podman run \ - --rm \ - -v /run/secrets/postgres-url:/run/secrets/postgres-url:ro \ - -e DATABASE_URL_FILE=/run/secrets/postgres-url \ - -e MODE=worker \ - -e WORKER_GROUP=default \ - -e ENABLE_UNSHARE_PID="true" \ - -e UNSHARE_ISOLATION_FLAGS="--user --map-root-user --pid --fork" \ - -v /tmp/storage-run-1000/podman/podman.sock:/var/run/docker.sock \ - -v /worker-logs:/tmp/windmill/logs \ - -v /worker-dependency-cache:/tmp/windmill/cache \ - --name worker \ - --network host \ - ghcr.io/windmill-labs/windmill:main & - -child=$! -trap _term SIGTERM -wait "$!"