Skip to content

Commit b11f137

Browse files
authored
Merge pull request #140 from joeyparrish/ephemeral
feat: Ephemeral mode
2 parents fdd8a7d + 53089f4 commit b11f137

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ RUN chmod +x /actions-runner/install_actions.sh \
1717
&& /actions-runner/install_actions.sh ${GH_RUNNER_VERSION} ${TARGETPLATFORM} \
1818
&& rm /actions-runner/install_actions.sh
1919

20-
COPY token.sh entrypoint.sh /
21-
RUN chmod +x /token.sh /entrypoint.sh
20+
COPY token.sh entrypoint.sh ephemeral-runner.sh /
21+
RUN chmod +x /token.sh /entrypoint.sh /ephemeral-runner.sh
2222

2323
ENTRYPOINT ["/entrypoint.sh"]
2424
CMD ["/actions-runner/bin/runsvc.sh"]

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,56 @@ docker run -d --restart always --name github-runner \
315315
-v /tmp/github-runner-your-repo:/tmp/github-runner-your-repo \
316316
myoung34/github-runner:latest
317317
```
318+
319+
## Ephemeral mode
320+
321+
GitHub's hosted runners are completely ephemeral. You can remove all its data without breaking all future jobs.
322+
323+
To achieve the same resilience in a self-hosted runner:
324+
1. override the command for your runner with `/ephemeral-runner.sh` (which will terminate after one job executes)
325+
2. don't mount a local folder into `RUNNER_WORKDIR` (to ensure no filesystem persistence)
326+
3. run the container with `--rm` (to delete it after termination)
327+
4. wrap the container execution in a system service that restarts (to start a fresh container after each job)
328+
329+
Here's an example service definition for systemd:
330+
331+
```
332+
# Install with:
333+
# sudo install -m 644 ephemeral-github-actions-runner.service /etc/systemd/system/
334+
# sudo systemctl daemon-reload
335+
# sudo systemctl enable ephemeral-github-actions-runner
336+
# Run with:
337+
# sudo systemctl start ephemeral-github-actions-runner
338+
# Stop with:
339+
# sudo systemctl stop ephemeral-github-actions-runner
340+
# See live logs with:
341+
# journalctl -f -u ephemeral-github-actions-runner.service --no-hostname --no-tail
342+
343+
[Unit]
344+
Description=Ephemeral GitHub Actions Runner Container
345+
After=docker.service
346+
Requires=docker.service
347+
348+
[Service]
349+
TimeoutStartSec=0
350+
Restart=always
351+
ExecStartPre=-/usr/bin/docker stop %n
352+
ExecStartPre=-/usr/bin/docker rm %n
353+
ExecStartPre=-/usr/bin/docker pull myoung34/github-runner:latest
354+
ExecStart=/usr/bin/docker run --rm --env-file /etc/ephemeral-github-actions-runner.env --name %n myoung34/ephemeral-github-actions-runner:latest /ephemeral-runner.sh
355+
356+
[Install]
357+
WantedBy=multi-user.target
358+
```
359+
360+
And an example of the corresponding env file that the service reads from:
361+
362+
```
363+
# Install with:
364+
# sudo install -m 600 ephemeral-github-actions-runner.env /etc/
365+
REPO_URL=https://github.com/your-org/your-repo
366+
RUNNER_NAME=your-runner-name-here
367+
ACCESS_TOKEN=foo-access-token
368+
RUNNER_WORKDIR=/tmp/runner/work
369+
LABELS=any-custom-labels-go-here
370+
```

ephemeral-runner.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
echo "*** Starting ephemeral runner. ***"
4+
/actions-runner/run.sh --once
5+
rv=$?
6+
7+
# See exit code constants in the runner source here:
8+
# https://github.com/actions/runner/blob/be96323/src/Runner.Common/Constants.cs#L135
9+
if [[ $rv == 4 ]]; then
10+
# The runner software was updated.
11+
echo "*** Software update detected. ***"
12+
13+
echo "*** Waiting for update to complete. ***"
14+
# Hard-coded sleep. Without some delay, the update is still in progress in
15+
# the background, leading to failures when we re-launch.
16+
sleep 10
17+
18+
# Now add an adaptive delay, where we loop and check if the Runner is usable
19+
# yet. As soon as it is, break.
20+
for i in $(seq 10); do
21+
if /actions-runner/bin/Runner.Listener --version &>/dev/null; then
22+
break
23+
fi
24+
25+
echo "*** Update still in progress... ***"
26+
sleep 5
27+
done
28+
29+
# Now re-launch the script.
30+
echo "*** Re-launching runner. ***"
31+
exec "$0"
32+
fi
33+
34+
# For any other return value, let the script and the Docker container terminate.
35+
echo "*** Exit code $rv ***"
36+
exit $rv

0 commit comments

Comments
 (0)