foreman-proxy container exhausts its pids limit under remote execution
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Domain
- devops, infrastructure
Research direction
Start by tracing how foremanctl builds and starts the foreman-proxy container, especially where PodmanArgs is configured; the issue reports that --init reaps orphaned processes, while Init=true makes quadlet delete the unit. Check the generated unit and run a proxy through repeated remote executions. Done means the supported configuration starts a real init as PID 1 and the container's pids count returns to baseline after jobs.
Written by the indexing model from the issue text.
Description
The foreman-proxy container never reaps the processes its remote-execution providers create. Each host execution leaves zombies behind for the life of the container, and podman's default pids limit of 2048 is low enough that a busy proxy reaches it after a few hundred host executions. At that point nothing in the container can fork and the proxy stops serving its API.
PID 1 in the container is the Ruby smart-proxy process (Name: smart-proxy, PPid: 0). Both providers start ssh clients that outlive the process that forked them: the script provider runs each execution under unshare --fork --kill-child with ControlMaster=auto and ControlPersist=yes, and the Ansible provider sets the same ControlPersist=yes in ANSIBLE_SSH_ARGS. In both cases the control master detaches, is reparented to PID 1, and is never waited on, so it stays in Z state. pids.current is effectively the zombie count and only grows. Nothing in foremanctl sets a pids limit, so podman's default applies.
The cost is about four pids per host for the script provider and about two for the Ansible provider. Both are cumulative, so the Ansible path reaches the same limit with roughly twice as many hosts — it is half the rate, not immune.
When the limit is reached the container logs:
sh: fork: retry: Resource temporarily unavailable
The proxy stops answering on its API port, and hosts whose content source is that proxy fail undispatched instead of moving to another capsule, so the impact is wider than the hosts the proxy was executing.
On the same deployment, capsules started with --init ran several hundred hosts each at 100%, while capsules with the same pids limit and no init failed every host they were given. The limit was not the variable. The same held for repeated Ansible jobs: the --init proxies accumulated no zombies at all while the default ones grew steadily. Of all containers on the host, only foreman-proxy accumulated zombies in quantity; every other container had none, apart from one service with a handful.
The container needs a real init as PID 1 so that orphaned processes are reaped. Starting it with --init does that: with the equivalent PodmanArgs=--init drop-in, pids return to baseline after each job instead of climbing, and proxies at the default limit execute their full host set. Init=true must not be used — quadlet rejects that key, deletes the unit, and the service does not come back.
- Dominant language
- Python
- Stars
- 26
- Forks
- 56
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 34
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from theforeman/foremanctl
-
Stop checking the removed Katello event daemonPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
theforeman/foremanctl#913 ·
Maintainers usually reply within 1 day
-
Wait for Foreman tasks in backup integration testsPossibly taken @jakduch claimed this 43 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
theforeman/foremanctl#894 ·
Maintainers usually reply within 1 day
-
Serialize image service pullsPossibly taken @jakduch claimed this 44 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
theforeman/foremanctl#881 ·
Maintainers usually reply within 1 day
-
Use a larger fapolicyd subject cache in deployment testsPossibly taken @jakduch claimed this 43 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
theforeman/foremanctl#880 ·
Maintainers usually reply within 1 day
-
Avoid privilege escalation timeout while waiting for PostgreSQLPossibly taken @jakduch claimed this 45 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
theforeman/foremanctl#862 ·
Maintainers usually reply within 1 day
All issues in theforeman/foremanctl
Similar issues
-
`destroy` sans terminal répond « Aborted. » au lieu de réclamer `--yes` comme `clean` et `reset`Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
stephrobert/dsoxlab#354 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
jasonacox/pypowerwall#472 ·
Maintainers usually reply within 1 day
-
[Bug]: DoubleMLRDDData accepts a score_col that is no data column (as in its docstring example); the running variable then becomes a covariate and RDFlex failsPossibly taken @vrjdev claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
DoubleML/doubleml-for-py#455 ·
Maintainers usually reply within 1 day
-
[Bug]: Python mod.Box[T] annotation gets a false generic_arg edge that replaces the parameter_type one ('is' on tree-sitter nodes)Possibly taken @rohit-jsfreaky claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Graphify-Labs/graphify#5110 · 1 comment ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
assafelovic/gpt-researcher#2277 ·
Maintainers usually reply within 10 days