Page MenuHomePhabricator

Deploy zuul executor on executor VM
Closed, ResolvedPublic

Description

Executor:

  • Set privileged flag
  • Bind mount a directory with the global nodepool ssh private key (if you want, you can put this under /etc/zuul or /var/lib/zuul so you don't need an extra mount point)
  • Bind mount /var/lib/zuul to the host. The executor uses this for its git repo cache and its builds in addition to the items noted above. This is specified as a VOlUME in the image, but we should avoid using a docker volume for this for efficiency and so that we can maintain the cache if we reset the docker configuration.
  • Listens on port 7900 for internal connections from zuul-web and zuul-fingergw only (for log streaming)
  • executor: docker-registry.wikimedia.org/repos/releng/zuul/zuul/zuul-executor:wmf-12.0.0-5

Summary of the above:

  • Will need a systemd unit to run docker-registry.wikimedia.org/repos/releng/zuul/zuul/zuul-executor:wmf-12.0.0-5 in privileged mode
  • The running container will need a bind mount with an ssh key allowing the zuul user to access the nodepool node
  • Needs to allow connections from the zuul-web/fingergateway node on port 7900
  • Will need a bind mount to /var/lib/zuul on the host. This will be a large, active volume, equivalent to /srv/zuul/git on the contint hosts.

Details

Related Changes in Gerrit:
SubjectAuthorRepoBranchLines +/-
Dzahnoperations/puppetproduction+2 -0
Dzahnoperations/puppetproduction+5 -0
Dzahnoperations/puppetproduction+8 -12
Dzahnoperations/puppetproduction+8 -0
Dzahnoperations/puppetproduction+4 -10
Dzahnoperations/puppetproduction+2 -2
Dzahnoperations/puppetproduction+13 -0
Dzahnoperations/puppetproduction+1 -1
Dzahnoperations/puppetproduction+14 -0
Dzahnoperations/puppetproduction+10 -0
Dzahnoperations/puppetproduction+3 -3
Dzahnoperations/puppetproduction+6 -0
Dzahnoperations/puppetproduction+1 -1
Dzahnoperations/puppetproduction+7 -0
Dzahnoperations/puppetproduction+8 -7
Dzahnoperations/puppetproduction+8 -2
Dzahnoperations/puppetproduction+8 -0
Show related patches Customize query in gerrit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
[zuul1002:/] $ sudo file /etc/zuul/ssh/id_rsa 
/etc/zuul/ssh/id_rsa: OpenSSH private key

Change #1185174 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul: define main and executor host names in common hiera data

https://gerrit.wikimedia.org/r/1185174

Change #1185174 merged by Dzahn:

[operations/puppet@production] zuul: define main and executor host names in common hiera data

https://gerrit.wikimedia.org/r/1185174

Change #1185180 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: firewall rule to allow main nodes to zuul-web port

https://gerrit.wikimedia.org/r/1185180

Change #1185180 merged by Dzahn:

[operations/puppet@production] zuul::executor: firewall rule to allow main nodes to zuul-web port

https://gerrit.wikimedia.org/r/1185180

Needs to allow connections from the zuul-web/fingergateway node on port 7900

zuul1002:~] $ sudo iptables -L | grep 7900
ACCEPT     tcp  --  zuul2001.codfw.wmnet  anywhere             tcp dpt:7900
ACCEPT     tcp  --  zuul1001.eqiad.wmnet  anywhere             tcp dpt:7900

Change #1185184 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: use profile::docker::engine to install docker

https://gerrit.wikimedia.org/r/1185184

Change #1185184 merged by Dzahn:

[operations/puppet@production] zuul::executor: use profile::docker::engine to install docker

https://gerrit.wikimedia.org/r/1185184

Change #1185196 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: ensure /var/lib/zuul dir exists

https://gerrit.wikimedia.org/r/1185196

Change #1185196 merged by Dzahn:

[operations/puppet@production] zuul::executor: ensure /var/lib/zuul dir exists

https://gerrit.wikimedia.org/r/1185196

executor.manage_ansible

It is recommended to set this to False and manually install Ansible after the Zuul installation by running zuul-manage-ansible.

We can't really do either of these things in production.

LSobanski changed the task status from Open to In Progress.Sep 8 2025, 3:38 PM
LSobanski triaged this task as High priority.
LSobanski moved this task from Incoming to Work in Progress on the collaboration-services board.

executor.manage_ansible

It is recommended to set this to False and manually install Ansible after the Zuul installation by running zuul-manage-ansible.

We can't really do either of these things in production.

The Zuul executor will run from a Docker image which already has Ansible installed:

$ docker run --rm -it --entrypoint=zuul-manage-ansible docker-registry.wikimedia.org/repos/releng/zuul/zuul/zuul-executor:wmf-12.0.0-5 -l
8
9 (default)

In the images, they are under /usr/local/lib/zuul/ansible.

Aha! Thanks for pointing that out. Good.

We need an /etc/zuul/zuul.conf specific to executors.

--> https://zuul-ci.org/docs/zuul/latest/configuration.html#id5

I see this config file in the zuul::main profile you set up. It looks to have the executor section which looks right. Need to ensure that (or part of that?) config file is on executors and that the path to the ssh key is correct for the bind mounts for the executor image.

Yes, let me try the simplest option first and ensure the same config file is deployed on both machines.

Change #1186045 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: add zuul config file

https://gerrit.wikimedia.org/r/1186045

Change #1186045 merged by Dzahn:

[operations/puppet@production] zuul::executor: add zuul config file

https://gerrit.wikimedia.org/r/1186045

Next step to debug is:

2025-09-08 20:01:28,869 ERROR zuul.BubblewrapDriver: Non zero return code
..
  File "/usr/local/lib/python3.11/dist-packages/zuul/driver/bubblewrap/__init__.py", line 224, in __init__
    raise Exception('bwrap execution validation failed. You can '
Exception: bwrap execution validation failed. You can use `zuul-bwrap /tmp id` to investigate manually.

Next step to debug is:

2025-09-08 20:01:28,869 ERROR zuul.BubblewrapDriver: Non zero return code
..
  File "/usr/local/lib/python3.11/dist-packages/zuul/driver/bubblewrap/__init__.py", line 224, in __init__
    raise Exception('bwrap execution validation failed. You can '
Exception: bwrap execution validation failed. You can use `zuul-bwrap /tmp id` to investigate manually.

where are you seeing that error? At a guess this might have to do with needing privileged mode, without that it's probably not able to effectively "wrap" things.

where are you seeing that error? At a guess this might have to do with needing privileged mode, without that it's probably not able to effectively "wrap" things.

[zuul1002:~] $ sudo docker tag 4ba8235d2c0b executor
..
[zuul1002:~] $ sudo docker run --privileged --mount type=bind,src=/etc/zuul,dst=/etc/zuul executor

It did not change between adding --privileged or not.

I am going to try to reduce the config file to just the executor part.

edit: Oh wait, I need to fix the path to the private key file. WIP

Change #1186567 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul(new): update path to ssh private key for zuul executor

https://gerrit.wikimedia.org/r/1186567

Change #1186567 merged by Dzahn:

[operations/puppet@production] zuul(new): update path to ssh private key for zuul executor

https://gerrit.wikimedia.org/r/1186567

running bubblewrap directly (zuul-wrap /tmp id mentioned in error message to debug)

[zuul1002:~] $ sudo docker run --privileged --mount type=bind,src=/etc/zuul,dst=/etc/zuul executor zuul-bwrap /tmp id
DEBUG:zuul.BubblewrapDriver:Initializing bubblewrap with oom_score_adj starting: 0, final: 200
DEBUG:zuul.BubblewrapExecutionContext:Bubblewrap command: setpriv --ambient-caps -all choom -n 200 -- bwrap --dir /tmp --tmpfs /tmp --dir /var --dir /var/tmp --dir /run/user/0 --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /bin /bin --ro-bind /sbin /sbin --ro-bind /etc/ld.so.cache /etc/ld.so.cache --ro-bind /etc/resolv.conf /etc/resolv.conf --ro-bind /etc/hosts /etc/hosts --ro-bind /etc/localtime /etc/localtime --ro-bind /dev/null /dev/null --bind /tmp /tmp --tmpfs /tmp/tmp --proc /proc --dev /dev --chdir /tmp --unshare-all --share-net --die-with-parent --uid 0 --gid 0 --file 3 /etc/passwd --file 4 /etc/group --unshare-user --disable-userns --ro-bind /lib64 /lib64 --ro-bind /etc/nsswitch.conf /etc/nsswitch.conf --ro-bind /etc/alternatives /etc/alternatives --ro-bind /etc/ssl/certs /etc/ssl/certs --ro-bind /etc/subuid /etc/subuid --ro-bind /etc/containers /etc/containers
ERROR:zuul.BubblewrapDriver:Non zero return code executing: setpriv --ambient-caps -all choom -n 200 -- bwrap --dir /tmp --tmpfs /tmp --dir /var --dir /var/tmp --dir /run/user/0 --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /bin /bin --ro-bind /sbin /sbin --ro-bind /etc/ld.so.cache /etc/ld.so.cache --ro-bind /etc/resolv.conf /etc/resolv.conf --ro-bind /etc/hosts /etc/hosts --ro-bind /etc/localtime /etc/localtime --ro-bind /dev/null /dev/null --bind /tmp /tmp --tmpfs /tmp/tmp --proc /proc --dev /dev --chdir /tmp --unshare-all --share-net --die-with-parent --uid 0 --gid 0 --file 3 /etc/passwd --file 4 /etc/group --unshare-user --disable-userns --ro-bind /lib64 /lib64 --ro-bind /etc/nsswitch.conf /etc/nsswitch.conf --ro-bind /etc/alternatives /etc/alternatives --ro-bind /etc/ssl/certs /etc/ssl/certs --ro-bind /etc/subuid /etc/subuid --ro-bind /etc/containers /etc/containers id
Traceback (most recent call last):
  File "/usr/local/bin/zuul-bwrap", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/zuul/driver/bubblewrap/__init__.py", line 353, in main
    driver = BubblewrapDriver(check_bwrap=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/zuul/driver/bubblewrap/__init__.py", line 224, in __init__
    raise Exception('bwrap execution validation failed. You can '
Exception: bwrap execution validation failed. You can use `zuul-bwrap /tmp id` to investigate manually.

"On systems with AppArmor (common on Ubuntu), it may be restricting bwrap's ability to create namespaces, even with the --privileged flag. You can try disabling AppArmor restrictions for unprivileged user namespaces."

Yea, we have apparmor installed. Testing that.

"Option 2: Add --disable-userns to the bwrap command"

And this.

I tried:

  • adding --security-opt seccomp=unconfined to docker command

    (" Docker's default seccomp (Secure Computing) profile, which is used even in privileged containers, blocks certain system calls (syscalls) that bwrap needs to create new namespaces")
  • adding --cap-add=SYS_ADMIN --cap-add=CAP_SYS_ADMIN to docker command

    ("Capabilities and setpriv: setpriv --ambient-caps -all may not function as expected in all nested container scenarios. By explicitly adding the CAP_SYS_ADMIN capability via --cap-add, you provide the necessary permissions for bwrap to create the required namespaces, such as user and mount namespaces.")
  • disabling apparmor on host system
  • adding --disable-userns to zuul-bwrap command

There is also a difference between bwrap and zuul-bwrap.

bwrap is version 0.8.0. ("Zuul versions 0.8.0 and newer are designed to detect if the host is using user namespaces and automatically add the --disable-userns flag to the bwrap command")

zuul-bwrap always fails with the Exception: bwrap execution validation failed. even with just --version.

bwrap can be executed.

Checked if this also happens on trixie with newer kernel version and on cloud VPS where production defaults for docker settings and kernel parameters don't apply.

Same issue.

Played around a bit with this. It looks like zuul-bwrap is trying to use bwrap.

I found a minimal repro case: bwrap --unshare-user --disable-userns --dev-bind / / /usr/bin/id

Docs say that creates a new user namespace then prevents sub user namespaces.

I straced it:

root@cb13e865c29b:/# strace -f -e trace=unshare,clone,setns,prctl bwrap --unshare-user --disable-userns --dev-bind / / /usr/bin/id 2>&1
...blah blah blah...
clone(child_stack=NULL, flags=CLONE_NEWNS|CLONE_NEWUSER|SIGCHLDstrace: Process 1240 attached
) = 1240
[pid  1239] prctl(PR_SET_DUMPABLE, SUID_DUMP_USER) = 0
[pid  1240] prctl(PR_CAPBSET_DROP, CAP_PERFMON) = 0
[pid  1240] prctl(PR_CAPBSET_DROP, CAP_BPF) = 0
[pid  1240] prctl(PR_CAPBSET_DROP, CAP_CHECKPOINT_RESTORE) = 0
[pid  1240] unshare(CLONE_NEWUSER)      = -1 EPERM (Operation not permitted)
bwrap: unshare user ns: Operation not permitted
[pid  1240] +++ exited with 1 +++
+++ exited with 1 +++

So it creates a new usernamespace using clone. Then when it tries to unshare in that namespace, it fails.

I kinda wonder if it's:

thcipriani@zuul1002:~$ cat /proc/sys/kernel/unprivileged_userns_clone 
1

which is different on my localhost vs. in this vm. I don't know, @dduvall do you remember anything like this when you were setting up a zuul executor in WMCS?

Found what makes a difference!

sudo sysctl -w kernel.unprivileged_userns_clone=1

makes the bwrap execution error go away!

Of the other options I tried above only --privileged is still needed.

Change #1186630 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: include profile::pki::client

https://gerrit.wikimedia.org/r/1186630

Change #1186630 merged by Dzahn:

[operations/puppet@production] zuul::executor: add TLS certs for zookeeper config

https://gerrit.wikimedia.org/r/1186630

@thcipriani

sudo docker run --privileged --mount type=bind,src=/etc/zuul,dst=/etc/zuul --mount type=bind,src=/var/lib/zuul,dst=/var/lib/zuul --mount type=bind,src=/etc/cfssl,dst=/etc/cfssl executor
...
2025-09-09 23:12:40,676 INFO zuul.Executor: Starting log streamer

:)

Just have to puppetize the correct path to the zookeeper TLS certs.. since it includes the host name and therefore changes on each machine.

But after I manually changed the path to the certs and added another bind mount for /etc/cfssl ... executor starts !

Change #1187055 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: systctl setting unprivileged_userns_clone needed

https://gerrit.wikimedia.org/r/1187055

Change #1187076 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul: use variables to set path to zookeeper TLS certs in config

https://gerrit.wikimedia.org/r/1187076

Change #1187076 merged by Dzahn:

[operations/puppet@production] zuul: use variables to set path to zookeeper TLS certs in config

https://gerrit.wikimedia.org/r/1187076

Change #1187055 merged by Dzahn:

[operations/puppet@production] zuul::executor: systctl setting unprivileged_userns_clone needed

https://gerrit.wikimedia.org/r/1187055

Change #1187495 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: use sysctl setting from base module, remove local code

https://gerrit.wikimedia.org/r/1187495

Change #1187495 merged by Dzahn:

[operations/puppet@production] zuul::executor: use sysctl setting from base module, remove local code

https://gerrit.wikimedia.org/r/1187495

Change #1187531 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: create systemd service

https://gerrit.wikimedia.org/r/1187531

Change #1187531 merged by Dzahn:

[operations/puppet@production] zuul::executor: create systemd service

https://gerrit.wikimedia.org/r/1187531

Change #1187899 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: fix name of systemd service template

https://gerrit.wikimedia.org/r/1187899

Change #1187899 merged by Dzahn:

[operations/puppet@production] zuul::executor: fix name of systemd service template

https://gerrit.wikimedia.org/r/1187899

Change #1187901 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: fix service description and path in systemd unit

https://gerrit.wikimedia.org/r/1187901

Change #1187901 merged by Dzahn:

[operations/puppet@production] zuul::executor: fix service description and path in systemd unit

https://gerrit.wikimedia.org/r/1187901

Change #1188844 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: hiera'ize docker image version and use in template

https://gerrit.wikimedia.org/r/1188844

Change #1188844 merged by Dzahn:

[operations/puppet@production] zuul::executor: hiera'ize docker image version and use in template

https://gerrit.wikimedia.org/r/1188844

Change #1188907 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: drop bootstrap file, adjust systemd service command line

https://gerrit.wikimedia.org/r/1188907

Change #1188907 merged by Dzahn:

[operations/puppet@production] zuul::executor: drop bootstrap file, adjust systemd service command line

https://gerrit.wikimedia.org/r/1188907

Change #1188911 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: configure exit code 143 as success in systemd unit

https://gerrit.wikimedia.org/r/1188911

Change #1188911 merged by Dzahn:

[operations/puppet@production] zuul::executor: configure exit code 143 as success in systemd unit

https://gerrit.wikimedia.org/r/1188911

Change #1189604 had a related patch set uploaded (by Dzahn; author: Dzahn):

[operations/puppet@production] zuul::executor: let executor connect to zookeeper on the host machine

https://gerrit.wikimedia.org/r/1189604

Change #1189604 merged by Dzahn:

[operations/puppet@production] zuul::executor: let executor connect to zookeeper on the host machine

https://gerrit.wikimedia.org/r/1189604

If I am strict about the wording of this ticket then it's resolved.

executor is deployed.

whether it works together with the other components is to be tested though

I am claiming this as resolved.. an executor is deployed. And we have a separate task that will be about testing the whole setup once other missing parts have been created.

Since https://gerrit.wikimedia.org/r/c/operations/puppet/+/1275972 added a firewall rule the executors can now talk to zookeeper on the main machines.