actions / runner

The Runner for GitHub Actions :rocket:
https://github.com/features/actions
MIT License
4.82k stars 949 forks source link

Provide an installer for running in a service account on self hosted Mac #947

Open ericvergnaud opened 3 years ago

ericvergnaud commented 3 years ago

Thank you πŸ™‡β€β™€ for wanting to create a feature in this repository. Before you do, please ensure you are filing the issue in the right place. Issues should only be opened on if the issue relates to code in this repository.

If you have a feature request that is relevant to this repository, the runner, then please include the information below:

Describe the enhancement Currently the Github action runner service can only be installed by an interactive user. This goes against what one expects from a CI i.e. run as a service independently of any user logged in.

Code Snippet Not relevant

Additional information Whilst it may seem a good idea to have 1 user account open a session automatically at startup, and have multiple runners installed under that user account (by running the Github agent runner many times with different names and tokens), it is not practical. Software such as Maven relies on a single .settings.xml tied to the account, so 4 runners running maven in parallel would compete and potentially corrupt the maven repo. This is just one example. We need n accounts in order to have more than 1 runner per self-hosted Mac. And they need to be service accounts in order for the runner to restart automatically.

Creating a service account on a Mac is quite difficult (there is no adduser) but it's possible (see attached). You can then su into the service account and install the standard runner (see attached). However, you'll find that the action runner service fails to run. There are many causes for that: missing dirs (Library/LaunchAgents...), authorizations...

What would be really great would be the following: -when initiating creation of a self-hosted runner from the Github UI, propose selection between UI account and service account

create-action-runner.txt create-ci-users.txt

NOTE: if the feature request has been agreed upon then the assignee will create an ADR. See docs/adrs/README.md

TingluoHuang commented 3 years ago

maybe https://github.com/actions/runner/blob/main/scripts/create-latest-svc.sh will help?

ericvergnaud commented 3 years ago

Hi, thanks, this is useful to automate the service creation. But I 'm not sure it addresses the fundamental issues with the service itself:

NRay7882 commented 3 years ago

This is a big issue currently with our automated deployments. AWS MacOS machines use ec2-macos-init to kickoff user_data scripts, we want to configure & deploy our runner as part of this process but cannot do so because the ec2-macos-init process runs as root.

From the runner directory, if I run su - ec2-user -c "/Users/ec2-user/actions-runner/svc.sh install" the script complains Must run from runner root or install is corrupt about the TEMPLATE_PATH=./bin/actions.runner.plist.temp reference. And using ./svc.sh install / /Users/ec2-user/actions-runner/svc.sh install just produces the Must not run with sudo error.

It would be a lot more convenient if there was ServiceRunAs flag or a way to pass a working path so the svc.sh generated has full directory paths used within instead. For now I'm going to investigate running a secondary init script outside of our user_data configuration.

EDIT: I also tried using @TingluoHuang's recommendation, however the create-latest-svc.sh script produces the same "Could not find domain for port (Aqua)" error when I try to install & run the svc.sh non-interactively. This is the closest I can get to automating the installation, it creates an Offline runner that becomes Idle after logging into the Mac with the user account via VNC.

mad01 commented 2 years ago

@NRay7882 to get around the aqua problem you need to run as a Daemon. you can place the plist in /Library/LaunchDaemons for example if you want the runner to come up after reboot.

this has to do with what is loaded in the different domains. in the Aqua domain the keychains is loaded for example. In our builds we use a temporary keychain with created by fastlane to not have to rely on the OS keychain

related to #349

NRay7882 commented 2 years ago

@NRay7882 to get around the aqua problem you need to run as a Daemon. you can place the plist in /Library/LaunchDaemons for example if you want the runner to come up after reboot.

this has to do with what is loaded in the different domains. in the Aqua domain the keychains is loaded for example. In our builds we use a temporary keychain with created by fastlane to not have to rely on the OS keychain

related to #349

TY @mad01 πŸ‘ , I'm testing how the agent comes online with the different plist settings. I was hoping we could use a non-interactive approach via SSH that doesn't require a reboot or desktop UI login altogether.

We also create the temp Keychain via Fastlane but this occurs currently as part of the iOS build process and not during the init of the machine itself.

brandonbirdj commented 2 years ago

I have solution in https://github.com/actions/runner/pull/1102 please add πŸ‘ to that pull request. Hopefully we can convince the maintainers to merge it.

ericvergnaud commented 2 years ago

If I understand correctly, #1102 only fixes half of the problem We would still need a change such that service is in LaunchDaemons rather than LaunchAgents?

brandonbirdj commented 2 years ago

If I understand correctly, #1102 only fixes half of the problem We would still need a change such that service is in LaunchDaemons rather than LaunchAgents?

@ericvergnaud apologies yes it only solves half of the issue. In addition to the the change in that PR, my other workaround is to have configured automatic login on our self-hosted runners so that the process always starts.

ericvergnaud commented 2 years ago

@brandon-bird-yolabs

Hi,

it seems that #1102 plus a change to darwin.svc/sh.template, line 18, replacing: LAUNCH_PATH="${HOME}/Library/LaunchAgents" with: LAUNCH_PATH="${HOME}/Library/LaunchDaemons" would do the trick ?

Can you confirm and if so, add the above to #1102, then I'll support it :-)

tcptps commented 1 year ago

My fancy new PR #2450 should fix this for good without the need for root privliges as the solution proposed by @ericvergnaud would require. if anybody were to check and verify if it works for them as well, I'd be very thankfull.

tcptps commented 1 year ago

The Problem of required GUI login, reboot and access should be dealt with by my PR above. (First time GUI login is most likely still required by the PR solution, but could be solved using the deamon workaround mentioned below) The PR however does not solve the problem of multiple users so here a few hints.

  1. * the service is installed in the user's Library/LaunchAgents, so only starts when the user logs in, not when the computer starts

    This is the problem we ultimatly face and if you want to create multiple users we have to use root during setup anywas.

  2. as a general improvment use boostrap instead of the legacy load along with my PR for example launchctl bootstrap user/$UID "${PLIST_PATH}" and launchctl bootout user/$UID "${PLIST_PATH}" the only probem is some older systems might not support boostrap. Resolves all of the issues my 2449 PR resolves (obviously not 2450 but that doesnt matter)

  3. you can boostrap an agent for any user regardless of login status by running: sudo launchctl bootstrap user/<uid> /Library/LaunchAgents/com.example.app.plist but be aware you might have to enable the service first (afaik only once) sudo launchctl enable user/<uid>/<label> /Library/LaunchAgents/com.example.app.plist Label from the plist file (more info on label) in this case most likely com.example.app

  4. You can boostrap a complete user domain sudo launchctl bootstrap user/<uid>

  5. You could bootstrap all agents using a script run as a deamon.

  6. Worse case scenario use the LoginWindow context

  7. A UserName key exits for the plist files but only applies to deamons: see launchd.info

  8. maybe try to do something as another user by running sudo launchctl asuser <uid> /bin/bash be careful you may be promted with a root shell, but it works regardless.

more general info and hints

btw I cant get su or login to work on service accounts.

Examples **Setup** created service user using GUI ```bash sudo launchctl enable user/511/test.com.example.app /Library/LaunchAgents/com.test.inc.testagent.plist sudo launchctl bootstrap user/511 /Library/LaunchAgents/com.test.inc.testagent.plist sudo launchctl bootout user/511 ``` pre verify: `launchctl dumpstate | grep 511 -m1` be careful this `$ launchctl print user/511 `will also start the bootsrap /Library/LaunchDaemons/com.test.inc.testagent.plist ```xml Label test.com.example.app Program /tmp/alpha.sh RunAtLoad ``` /tmp/alpha.sh ```bash #!/bin/bash sudo launchctl bootstrap user/511 ``` /Library/LaunchAgents/com.test.inc.testagent.plist ```xml LimitLoadToSessionType Aqua LoginWindow Background StandardIO Label test.com.example.app Program /Users/Me/Scripts/cleanup.sh RunAtLoad ``` launch: `sudo launchctl bootstrap system /Library/LaunchDaemons/com.test.inc.testagent.plist` verify afterwards: ``` bash $ sudo launchctl dumpstate | grep 511 -m3 com.apple.xpc.launchd.domain.user.511 ``` and: ```bash $ sudo launchctl print user/511 | grep -m1 test 0 - test.com.example.app ``` This way no old stuff gets broken by moving plist files from agents to deamons