Debugging GitHub CI Actions
The GitHub CI Actions for my favorite open-source project, the bookmarking service Shaarli, started failing recently. No one was quite sure why, especially because there hadn’t been any significant updates to the tests, and they passed locally for all the developers who ran them. I had a small pull request that was failing as well, so I thought I would give fixing the actions a shot.
The first step I took was to try to a print-statement approach on my own fork of the project. This involved making changes on my local machine, pushing them to GitHub, then waiting to see the results of the CI Actions. It got me nowhere. What I really needed was a way to replicate how GitHub ran the actions on my local machine.
Tools required
I have access to a few different OS’s locally, but they all had their pros and cons. Ultimately, I used WSL (Ubuntu 22.04) and it worked great. In the future, I might try to replicate the environment on an M1 Mac.
The tool for running GitHub Actions locally is called act
. It is written in Golang, so you’ll need to install that first. To install it on WSL I used:
$ curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
You’ll also need Docker. Of course nothing is easy and I went with the docker-ce
version. To run Docker as your user (instead of root), add your user to the docker group and log back in.
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get install docker-ce
$ sudo usermod -aG docker $USER
<re-log-in>
$ sudo systemctl start docker
$ docker run hello-world
Setting up the back-end
It’s possible to run act
with a default docker image, but I found it didn’t perfectly match how the GitHub Actions for Shaarli were run. I created my own Dockerfile with Shaarli’s dependencies. Mostly, I needed to install nodejs
for the action to work properly. I also set the user to be ‘runner’, which is the GitHub Actions default user. Otherwise, the action would run under root, which is not what we want.
It made sense to put the Dockerfile under the .github/
directory for the project, so I created .github/act/Dockerfile
:
FROM ubuntu-latest
# Install necessary dependencies
RUN apt-get update && apt-get install -y \
sudo \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
# Get correct version of nodejs
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - \
&& sudo apt install -y nodejs
# Create a non-root user (same as GitHub Actions)
RUN useradd -m runner && \
echo "runner ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Set user to 'runner'
USER runner
# Set working directory (GitHub Actions uses this location)
WORKDIR /home/runner
CMD ["/bin/bash"]
There was definitely some experimentation required to get Shaarli’s actions running correctly, and I suspect every project has slightly different requirements.
Now, we can build and run the back-end Docker image, which in my case I named ‘shaarli’.
$ docker build -t shaarli .github/act
$ docker images
Running act
Finally, we can use act
to run the GitHub Actions locally. We use our docker image (shaarli) instead of ubuntu-latest in the ci.yaml file. The --pull=false
argument tells act the docker image is local. The -j
option will run a specific job instead of the entire suite.
$ act -P ubuntu-latest=shaarli --pull=false -j php
If you want to ssh into the running image to further debug the action, use act --bind
to keep it running. Find the container ID and run bash:
$ docker ps
$ docker exec -it 6ffdb /bin/bash
Other Docker utilities
This is definitely an iterative process. Here are some commands for cleaning up the Docker containers and images:
$ docker kill $(docker ps -a -q)
$ docker rm $(docker ps -a -q)
$ docker rmi $(docker images -a -q)
Debugging directly at GitHub
As a last resort (maybe?), you can even debug actions directly on GitHub using action-tmate. Add the following to your ci.yml file:
steps:
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
The Actions details will show a host you can SSH into to get inside the container.
Good luck with your debugging!