Utilizing Docker within Actions
Forgejo Runner uses a container environment to run actions, but additional configuration is required to allow actions to access a container environment as well.
For example, a simple Forgejo workflow like this:
name: Docker Build
on:
push:
branches: [main]
jobs:
build:
runs-on: docker
steps:
- uses: actions/checkout@v6
- run: docker build -t my-app .
Will typically fail with an error like this:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Why doesn’t it just work?
The job container that Forgejo Runner executes doesn’t have access to a docker socket.
When the Forgejo Runner receives a job to execute, it will create a container which will be used to execute the job, the job container. The configuration of this container is usually defined by the labels on Forgejo Runner, but can also be configured within the job by the jobs.<job_id>.container.image (and related properties).
The individual steps in the workflow are executed within that job container. Without any special configuration, when a command like docker build executes within the job container it will attempt to reach out to a running docker daemon via the default UNIX socket /var/run/docker.sock. Accessing this socket will fail because there is no docker daemon available within the job container, even though the job container itself is being run and managed by docker.
As there are a number of different systems being described in this document, these terms will be used consistently to maintain clarity:
- Host
- The machine that is running the Forgejo Runner process.
- Job container
- When executing a job (example: the
buildsection of the above workflow), Forgejo Runner typically uses a container environment (Docker, Podman, or LXC) to start a job container. Forgejo Runner executes commands from the job in this job container. (Forgejo Runner can also execute commands directly on the host via a label...:host; as that configuration is not affected by the problem described it is out-of-scope of this document.)
- When executing a job (example: the
- Service container
- Some jobs define additional containers that are started at the same time as the job container. For example, it is typical to start a database engine such as MySQL or PostgreSQL in order to support integration testing with a database. Service containers are defined in the
jobs.<job_id>.servicessection of the workflow file.
- Some jobs define additional containers that are started at the same time as the job container. For example, it is typical to start a database engine such as MySQL or PostgreSQL in order to support integration testing with a database. Service containers are defined in the
Security Considerations
Providing Forgejo Actions workflows the ability to access a Docker daemon adds to the complex security requirements for Forgejo Runner. While choosing their desired configuration, an administrator of Forgejo Runner will want to be cautious that providing access to a Docker system doesn’t grant unexpected access to other resources in the same Docker system.
For example, assuming that both Forgejo and Forgejo Runner are using the same Docker daemon, granting direct access to that daemon would allow an executed Action to shut down the Forgejo instance (see diagram below), or perform far more dangerous actions like creating an administrator account with unlimited access to the instance. This may be an acceptable risk to the administrator, or it may be access that they would prefer to prevent.
Solutions
Docker-in-Docker
Forgejo Runner can be configured to use “Docker in Docker” (abbreviated as DIND) for Actions’ access to Docker. This involves running a separate “DIND” container that runs on the host’s Docker daemon, and provides its own isolated Docker daemon. When configured in this mode, attempts to access Docker will be redirected to the DIND container and will run there: