I just don't like GitHub Actions.
Tags: github, devops, automation
Published: 2020-04-23 11:16:00

---
title: I just don't like GitHub Actions.
published: true
description: GitHub Actions feels like an awesome concept, but the implementation just didn't do it for me.
tags: github, devops, automation
---

_I tried, I really did. Does anyone feel the same?_

GitHub Actions was launched in 2018 as a means of automating repetitive tasks. In 2019 it was updated with first-class support for continuous integration (CI) and continuous delivery (CD). The premise sounds very "GitHub":

* Developers can write Actions, which live in GitHub repos.
* Other developers can consume Actions in their own workflows based on GitHub events and webhooks.
* Software development and deployment involves working across platforms, so integrations are first-class.
* It all "just works", with a polished onboarding experience that can build and test many projects without manual configuration.

I’m writing about my personal experience, and your mileage may vary. My intent isn't to slate the feature, but to highlight some limitations of the current implementation and to put forward some ideas. I think my use case is quite different to that GitHub is trying to address with Actions, which I'll get to in the conclusion, but I think it's possible to accommodate it without compromising on what Actions already does well.

# Testing changes to workflows is painful

I started out by picking the _Docker build/push_ workflow template and editing it. I wanted to keep the versions of the tools consistent with those used for local development, so I used `docker-compose build` to build the images. I pushed my new workflow, and it failed because of a typo. No biggie, I fixed the typo and gave it a minute for the workflow to trigger, but it didn't. Maybe I needed to click the re-run button?

There's no means of easily triggering a re-run of a workflow against the tip of a branch. Not only is this a problem when dealing with transient failures (such as a network issue during an `npm install` or `docker pull`), it also makes development of new workflows or testing changes to existing workflows difficult.

It's possible to work around this by adding additional triggers, but it feels like a strange omission.

# No first-class support for running locally

This limitation seems common to many CI platforms: there's no obvious way to run a workflow locally to verify that it works. Third party tools like [Act](https://github.com/nektos/act) have put in a great deal of work to approximate the environment, but it's not easy to do so accurately.

Act works by executing your GitHub Action workflows in a container. The minimal Debian images it uses by default will be unable to run the majority of workflows, but it's possible to specify your own container image. Unfortunately, [the images that try to replicate the Actions environment](https://hub.docker.com/r/nektos/act-environments-ubuntu/tags) get very large. A 12GB Docker container isn't ideal.

# The VM images are big

To understand why we have to peek behind the curtain. Thankfully, the [images used by the virtual environment](https://github.com/actions/virtual-environments) are open source. Drilling down a little, we can see [a lot of scripted software installation](https://github.com/actions/virtual-environments/blob/44f2342c9e796a4d0c3bd36aff870b38abd6a71b/images/linux/ubuntu1804.json#L171-L227).

Shipping so many SDKs by default certainly improves the onboarding experience in the majority of cases -- it will reduce the amount of setup required to start seeing results. I imagine the standardisation makes it easier for Action developers to bring new build, linting and testing tools into the ecosystem.

Unfortunately, it also reduces predictability of builds, as developers have little control over what's installed in the environment. This has a couple of effects:

* In CI workflows it becomes harder to troubleshoot test failures, as it's harder to replicate the environment locally. It also makes your builds more susceptible to packaging changes made to the images, as there are far more changes to review to determine the root cause of a failure.
* In build and publish workflows it makes it difficult to trust that the environment is secure. Is GitHub reliably auditing all of the software that they're installing?

To work around this, I could perform all of my actions within containers. This would mean losing access to the existing library of Actions, except those that directly interact with Docker. I think there's a better way, though.

## Minimal base image with SDK add-ons?

Instead of, or maybe in addition to, the large images with all of the runtimes preinstalled, why not ship a lightweight base image with the ability to add on just the components we need? Workflows could specify that they want an SDK as follows:

```yaml
name: Docker images

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    # Just list your SDKs here
    runs-with:
      - docker

    steps:
      - uses: actions/checkout@v2
      - name: Build the Docker images
        run: docker-compose -f docker-compose.build.yml build
```

Developers of Actions should be able to specify SDK dependencies too, so users of Actions could remain oblivious to the inner workings.

Since this doesn't yet exist, let's move on to another option for now...

# Self-hosted runners

Actions provides the ability to host your own runners, so that your jobs can run on your own infrastructure and be triggered from within GitHub. This would allow us to build our own minimal image!

Unfortunately unlike services like Buildkite, which can [run your integration jobs on your own AWS subscription](https://buildkite.com/docs/tutorials/elastic-ci-stack-aws), Actions provides no way to dynamically allocate agents as they're required.

I'd like to see support for provisioning runners from my own images in my Azure or AWS subscription. Although more expensive, the additional control over the environment would allow me to work around many of these issues.

# Conclusion

I know my dependencies, and I’d rather build and deploy my applications in the most minimal environment possible than have so much preinstalled. I think GitHub Actions has some serious promise, even despite it not providing a more minimal environment for running tasks. The design could be extended to make it more viable for advanced use cases:

* Support for running workflows in public cloud environments would make using custom images much more accessible, and provide a fairly elegant workaround for most of the issues here.
* A more minimal base image should be available, at least as an option. I think it will be difficult to retroactively add in support for SDKs, as Actions would need to be updated to detail their dependencies or risk simply not working, harming the onboarding experience for the majority.
* An easier way of triggering runs of a workflow from the web would be ideal. Maybe edits to workflow files should trigger a run automatically, though we'd still need the ability to re-run jobs that may have failed due to transient failures.

*[AWS]: Amazon Web Services
*[CD]: Continuous Delivery
*[CI]: Continuous Integration
*[SDK]: Software Development Kit