Repository navigation
Support Runner inside of Docker Container #406
Description
Activity
There appear to be a couple more things that need to be done to account for multiple runners on the same host concurrently:
docker network prunecan not run concurrently and should likely be retried if such an error is received:/usr/local/bin/docker network prune --force --filter "label=898d1dec6adc" Error response from daemon: a prune operation is already running ##[warning]Delete stale container networks failed, docker network prune fail with exit code 1- The docker label is not sufficient for isolating separate runners on the same host. The current hash of the root directory will result in the same label being used for all runners with the exact same version. In my testing I've switched this to use the hostname, but perhaps something like the runner name or run ID could be used.
Reacted by Jesse Adelman@TingluoHuang @bryanmacfarlane I'm hoping to get your feedback on this – getting official support for this would be a huge help for me. I'm happy to work on an implementation if that is helpful.
Reacted by Iiro Niinikoski, Trevor Bossert, Fabrizio Sabatini, Salvador Sarpi, Christian Haschek, Kenneth Modrego, Ville Saukkonen, Robert W, pratikbin and Alessandro ReThis is a big problem for us. We want to run gh runner in docker to easier scaling and isolation. But we need to also run services for tests. So our workaround for now is to run multiple runners on host, but scaling container with docker-compose is so much easier and convenient.
Reacted by pratikbin and JleagleThis is a big problem for us. We want to run gh runner in docker to easier scaling and isolation. But we need to also run services for tests. So our workaround for now is to run multiple runners on host, but scaling container with docker-compose is so much easier and convenient.
Fully agree, for the time being we have build a scalable solution on AWS spot to server our docker builds. A detailed blog post en ref to the code https://040code.github.io/2020/05/25/scaling-selfhosted-action-runners
Reacted by Mike Chelen, nikoudel, pratikbin and ecoutThis is a big problem for us. We want to run gh runner in docker to easier scaling and isolation. But we need to also run services for tests. So our workaround for now is to run multiple runners on host, but scaling container with docker-compose is so much easier and convenient.
Currently we have to create workarounds using non-optimal solutions to deploy tens of runners - or workarounds for container usage in jobs which is rather ugly. How to raise priority of this ?
Just curious, how other's manage scaling the runners ? This is probably one of the most interested approach so far I've seen.. I guess many of us faced this same challenge when scaling gh-runners.. "Official" scaling proposals from GitHub would be more than welcome :) .
This is a big problem for us. We want to run gh runner in docker to easier scaling and isolation. But we need to also run services for tests. So our workaround for now is to run multiple runners on host, but scaling container with docker-compose is so much easier and convenient.
Big kudos for @npalm and its solution on AWS. We also build a similar solution for GCP allowing us to scale our self hosted runners for a whole GitHub organization https://github.com/faberNovel/terraform-gcp-github-runner
Reacted by Niek Palm, DJ Carpenter, Doug Balog, Mike Chelen, nikoudel, Sam Havens and pratikbin@jupe we use https://github.com/summerwind/actions-runner-controller which has worked really well for us so far
Reacted by Sean Fausett, Johannes Nicolai, Avdhoot Dendge, Doug Balog, Callum Tait, pratikbin and Ronan Barrettwaiting for this one so bad
Reacted by Dr. Uwe Daub, Scott Pierce, Doug Balog, John Molakvoæ and pratikbin@jpb Is there any possibility to get a higher priority on this?
Reacted by SimonPNorra, Alexej Kowalew, Scott Pierce, Doug Balog, gibsonje, Jooho Lee, John Molakvoæ, ping, pratikbin, Mikolaj and 2 moreFor now we will use some workaround based on docker-compose.
We have the following docker-compose.yaml file in the repo to setup the services.version: "3.3" services: nginx: image: nginx redis: image: redisWe then connect the self-hosted runner which is also running inside docker with the created network.
This is one example WF:name: Start docker compose on: workflow_dispatch: jobs: start-docker-compose: # should run as docker container with connection to the dockerd of the host runs-on: [self-hosted] steps: - name: Checkout code uses: actions/checkout@v2 with: fetch-depth: 1 - name: Start docker compose id: start-docker-compose run: | project_prefix=my-project project_name="${project_prefix}-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 | tr '[:upper:]' '[:lower:]')" my_container_id=$(grep docker /proc/self/cgroup | head -n 1 | sed "s|^.*/docker/\(.*\)|\\1|") docker-compose -p "${project_name}" up -d while ! docker network inspect "${project_name}_default" > /dev/null ; do sleep 1 done docker network connect "${project_name}_default" "${my_container_id}" echo "::set-output name=my_container_id::$my_container_id" echo "::set-output name=project_name::$project_name" - name: Check output run: | echo "Project name: ${{ steps.start-docker-compose.outputs.project_name}}" echo "Container ID: ${{ steps.start-docker-compose.outputs.remote_container_id}}" - name: Use the started docker compose services run: | # Install netcat to check redis apt-get update apt-get install -y netcat echo '--------------------' ping -c 1 nginx curl nginx echo '--------------------' ping -c 1 redis echo ping | netcat -w 2 redis 6379 - name: Cleanup started docker compose services if: always() run: | docker network disconnect ${{ steps.start-docker-compose.outputs.project_name}}_default ${{ steps.start-docker-compose.outputs.my_container_id}} docker-compose -p ${{ steps.start-docker-compose.outputs.project_name}} downReacted by pratikbinWe still want to do this and it's on our list but we don't have a date or schedule for shipping this type of feature right now.
Reacted by Mike Chelen, Daniel Mühlbachler-Pietrzykowski, Frédéric Simonis, Robert W, Alban , Jooho Lee, Jakob, Tom Plant, Umberto Baldi, Sindre Svendby and 5 moreReacted by Mike Chelen, Lei LI, John Molakvoæ, Robert W, Jooho Lee, pratikbin, Nick Paul, David Meents and Asım TahirWould love to see this prioritized. Can't really run docker-in-docker on Kubernetes self-hosted runners without this.
Reacted by Doug Balog, Kenneth Modrego, Umberto Baldi, Dr. Uwe Daub, Brandon Schabell, Nathan Brasher, Ilya Voronin, Bret Fisher, Thomas Barach, Vladyslav Riabets and 47 more26 remaining items
@Sebastian-0 I understand that there are limitations. But the way this issue is currently written does not say what these limitations are exactly. The way it is currently written, specially its title, can lead people to believe that is not possible to run the runner inside a container in any ways, which, after some trials, I discovered it is not true.
I know that there is a solution that allows the runner to run inside a docker container, because I was able to do it. However, this evidence alone does not prove that there isn't an edge case that won't work. So, that is why I'm asking an example of workflow that won't work with this solution. This can help other people to better understand what the real problem is.Reacted by Ercin Dedeoglu@AllanOricil, I do not think that this issue can be closed as long as there is no official guide/info on this such as:
- docker will not be supported
- to run in docker you need to ...image... entry point ... network … mounts ... etc that is kept up to date by the gh-actions team
Reacted by Code Talker, Kyle, Iceflower and Steven Kerautret@Sebastian-0 I understand that there are limitations. But the way this issue is currently written does not say what these limitations are exactly. The way it is currently written, specially its title, can lead people to believe that is not possible to run the runner inside a container in any ways, which, after some trials, I discovered it is not true. I know that there is a solution that allows the runner to run inside a docker container, because I was able to do it. However, this evidence alone does not prove that there isn't an edge case that won't work. So, that is why I'm asking an example of workflow that won't work with this solution. This can help other people to better understand what the real problem is.
@AllanOricil basically these items are not working: myoung34/docker-github-actions-runner#98
Meaning that in GitHub Actions you can't really get container services working/running that might be needed. I was getting failures when attempting to use the "Local Registry" solution for GitHub Actions when building Docker images in order to test them.
/usr/bin/docker create --name fc2ec27c43d44dc68880bee45a7b12fb_registry2_b6e2e5 --label c3f261 --network github_network_6886f8441d2f4f3489b19978db60872b --network-alias registry -p 5000:5000 -e GITHUB_ACTIONS=true -e CI=true registry:2 83b0180533c3ec325b50cff90[42](https://github.com/ndigitals/ols-dockerfiles/actions/runs/5920922473/job/16052814082#step:2:45)8487490e74aaa907a46ac8ae45f08bc866755 /usr/bin/docker start 83b0180533c3ec325b50cff90428487490e74aaa907a46ac8ae45f08bc866755 Error response from daemon: network github_network_6886f8[44](https://github.com/ndigitals/ols-dockerfiles/actions/runs/5920922473/job/16052814082#step:2:47)1d2f4f3489b19978db60872b not found Error: failed to start containers: 83b0180533c3ec325b50cff90428487490e74aaa907a46ac8ae[45](https://github.com/ndigitals/ols-dockerfiles/actions/runs/5920922473/job/16052814082#step:2:48)f08bc866755I was trying to use the following Local Registry GitHub Actions setup for Docker image builds.
Reacted by Allan OricilInteresting. Now it makes sense to me why this should not be closed. Thanks @timnolte
Reacted by Tim NolteI have setup dind using terraform and a custom image based on dind. That all ran in my local WSL2, so I assume it wouldn't be far fetched to do it for the other scenarios. In an approach similar to what @AllanOricil, I did have to setup a bridge network properly, which took a lot of trial and error, but in the end it worked, both with a shared socket and with an independent socket. I will share here what I did as is and maybe someone can pick it up from it.
This is not a solution, but whoever is having problems, may pickup some ideas from what I did:
Terraform code
Should be straightforward to convert it to anything else)
Network
resource "docker_network" "rke_network" { name = local.docker_network_name driver = "bridge" attachable = true internal = false ipam_config { ip_range = local.network_subnet subnet = local.network_subnet gateway = local.network_gateway } options = { "com.docker.network.bridge.enable_icc" = "true" "com.docker.network.bridge.enable_ip_masquerade" = "true" "com.docker.network.bridge.host_binding_ipv4" = "0.0.0.0" "com.docker.network.bridge.name" = local.iface_name "com.docker.network.driver.mtu" = "65000" "com.docker.network.driver.txqueuelen" = "10000" } provisioner "local-exec" { command = "sudo ip link set dev eth0 txqueuelen 10000 && sudo ip link set dev eth0 mtu 65000 && sysctl -w net/netfilter/nf_conntrack_max=393216" } }
Docker container node definition (where the agent would be)
resource "docker_container" "node" { count = 4 name = "rke-dind-${local.nodes[count.index].ipv4_address}" image = "docker.local/dind-ssh:latest" privileged = true publish_all_ports = true user = "root" cgroupns_mode = "host" ipc_mode = "shareable" stdin_open = true tty = true runtime = "runc" network_mode = "bridge" env = [ "DOCKER_TLS_CERTDIR=\"\"", "AUTH_PUBKEY=${tls_private_key.ssh_key.public_key_openssh}", "AUTH_PRVKEY=${tls_private_key.ssh_key.private_key_openssh}" ] networks_advanced { name = local.docker_network_name ipv4_address = local.nodes[count.index].ipv4_address } ports { internal = 22 ip = "0.0.0.0" protocol = "tcp" } ports { internal = 2375 ip = "0.0.0.0" protocol = "tcp" } ports { internal = 2376 ip = "0.0.0.0" protocol = "tcp" } ports { internal = 2379 ip = "0.0.0.0" protocol = "tcp" } }
Building a custom dind image
I did to enable ssh into it, but can also be used to add an agent for example.
The RSA keys you should generate one yourself as they are used in the image build process (but could also be generated otherwise during build). My use case required that I had these keys pre-made elsewhere.Dockerfile
FROM docker:dind AS dindssh # Install SSH server RUN apk add openssh-server # Generate SSH host keys RUN ssh-keygen -A # Copy sshd_config file COPY sshd_config /etc/ssh/sshd_config COPY daemon.json /etc/docker/daemon.json RUN chmod 700 /usr/local/bin/dockerd-entrypoint.sh COPY dockerd-entrypoint.sh /usr/local/bin/dockerd-entrypoint.sh RUN chmod +x /usr/local/bin/dockerd-entrypoint.sh # Add authorized keys for root user RUN mkdir -p /root/.ssh RUN touch /root/.ssh/authorized_keys RUN touch /root/.ssh/id_rsa RUN chmod 600 /root/.ssh/authorized_keys RUN chmod 600 /root/.ssh/id_rsa RUN chown root:root /root/.ssh/authorized_keys RUN chown root:root /root/.ssh/id_rsa # Expose SSH, Docker and etcd ports EXPOSE 22 2375 2379 # Start SSH daemon and Docker daemon ENTRYPOINT (/usr/sbin/sshd -D &) && dockerd-entrypoint.sh CMD []
Entrypoint file
Don't remember where I got the base file from, but it is highly customized to work with SSH + DIND
#!/bin/sh set -eu _tls_ensure_private() { local f="$1"; shift [ -s "$f" ] || openssl genrsa -out "$f" 4096 } _tls_san() { { ip -oneline address | awk '{ gsub(/\/.+$/, "", $4); print "IP:" $4 }' { cat /etc/hostname echo 'docker' echo 'localhost' hostname -f hostname -s } | sed 's/^/DNS:/' [ -z "${DOCKER_TLS_SAN:-}" ] || echo "$DOCKER_TLS_SAN" } | sort -u | xargs printf '%s,' | sed "s/,\$//" } _tls_generate_certs() { local dir="$1"; shift # if server/{ca,key,cert}.pem && !ca/key.pem, do NOTHING except verify (user likely managing CA themselves) # if ca/key.pem || !ca/cert.pem, generate CA public if necessary # if ca/key.pem, generate server public # if ca/key.pem, generate client public # (regenerating public certs every startup to account for SAN/IP changes and/or expiration) if [ -s "$dir/server/ca.pem" ] && [ -s "$dir/server/cert.pem" ] && [ -s "$dir/server/key.pem" ] && [ ! -s "$dir/ca/key.pem" ]; then openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" return 0 fi # https://github.com/FiloSottile/mkcert/issues/174 local certValidDays='825' if [ -s "$dir/ca/key.pem" ] || [ ! -s "$dir/ca/cert.pem" ]; then # if we either have a CA private key or do *not* have a CA public key, then we should create/manage the CA mkdir -p "$dir/ca" _tls_ensure_private "$dir/ca/key.pem" openssl req -new -key "$dir/ca/key.pem" \ -out "$dir/ca/cert.pem" \ -subj '/CN=docker:dind CA' -x509 -days "$certValidDays" fi if [ -s "$dir/ca/key.pem" ]; then # if we have a CA private key, we should create/manage a server key mkdir -p "$dir/server" _tls_ensure_private "$dir/server/key.pem" openssl req -new -key "$dir/server/key.pem" \ -out "$dir/server/csr.pem" \ -subj '/CN=docker:dind server' cat > "$dir/server/openssl.cnf" <<-EOF [ x509_exts ] subjectAltName = $(_tls_san) EOF openssl x509 -req \ -in "$dir/server/csr.pem" \ -CA "$dir/ca/cert.pem" \ -CAkey "$dir/ca/key.pem" \ -CAcreateserial \ -out "$dir/server/cert.pem" \ -days "$certValidDays" \ -extfile "$dir/server/openssl.cnf" \ -extensions x509_exts cp "$dir/ca/cert.pem" "$dir/server/ca.pem" openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" fi if [ -s "$dir/ca/key.pem" ]; then # if we have a CA private key, we should create/manage a client key mkdir -p "$dir/client" _tls_ensure_private "$dir/client/key.pem" chmod 0644 "$dir/client/key.pem" # openssl defaults to 0600 for the private key, but this one needs to be shared with arbitrary client contexts openssl req -new \ -key "$dir/client/key.pem" \ -out "$dir/client/csr.pem" \ -subj '/CN=docker:dind client' cat > "$dir/client/openssl.cnf" <<-'EOF' [ x509_exts ] extendedKeyUsage = clientAuth EOF openssl x509 -req \ -in "$dir/client/csr.pem" \ -CA "$dir/ca/cert.pem" \ -CAkey "$dir/ca/key.pem" \ -CAcreateserial \ -out "$dir/client/cert.pem" \ -days "$certValidDays" \ -extfile "$dir/client/openssl.cnf" \ -extensions x509_exts cp "$dir/ca/cert.pem" "$dir/client/ca.pem" openssl verify -CAfile "$dir/client/ca.pem" "$dir/client/cert.pem" fi } export DOCKER_HOST=/var/run/docker.sock # no arguments passed # or first arg is `-f` or `--some-option` if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then # set "dockerSocket" to the default "--host" *unix socket* value (for both standard or rootless) uid="$(id -u)" if [ "$uid" = '0' ]; then dockerSocket='unix:///var/run/docker.sock' else # if we're not root, we must be trying to run rootless : "${XDG_RUNTIME_DIR:=/run/user/$uid}" dockerSocket="unix://$XDG_RUNTIME_DIR/docker.sock" fi case "${DOCKER_HOST:-}" in unix://*) dockerSocket="$DOCKER_HOST" ;; esac # add our default arguments if [ -n "${DOCKER_TLS_CERTDIR:-}" ]; then _tls_generate_certs "$DOCKER_TLS_CERTDIR" # generate certs and use TLS if requested/possible (default in 19.03+) set -- dockerd \ --tlsverify \ --tlscacert "$DOCKER_TLS_CERTDIR/server/ca.pem" \ --tlscert "$DOCKER_TLS_CERTDIR/server/cert.pem" \ --tlskey "$DOCKER_TLS_CERTDIR/server/key.pem" \ "$@" DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2376:2376/tcp" else # TLS disabled (-e DOCKER_TLS_CERTDIR='') or missing certs set -- dockerd \ "$@" DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2375:2375/tcp" fi fi if [ "$1" = 'dockerd' ]; then # explicitly remove Docker's default PID file to ensure that it can start properly if it was stopped uncleanly (and thus didn't clean up the PID file) find /run /var/run -iname 'docker*.pid' -delete || : if dockerd --version | grep -qF ' 20.10.'; then # XXX inject "docker-init" (tini) as pid1 to workaround https://github.com/docker-library/docker/issues/318 (zombie container-shim processes) set -- docker-init -- "$@" fi if ! iptables -nL > /dev/null 2>&1; then # if iptables fails to run, chances are high the necessary kernel modules aren't loaded (perhaps the host is using nftables with the translating "iptables" wrappers, for example) # https://github.com/docker-library/docker/issues/350 # https://github.com/moby/moby/issues/26824 modprobe ip_tables || : fi uid="$(id -u)" if [ "$uid" != '0' ]; then # if we're not root, we must be trying to run rootless if ! command -v rootlesskit > /dev/null; then echo >&2 "error: attempting to run rootless dockerd but missing 'rootlesskit' (perhaps the 'docker:dind-rootless' image variant is intended?)" exit 1 fi user="$(id -un 2>/dev/null || :)" if ! grep -qE "^($uid${user:+|$user}):" /etc/subuid || ! grep -qE "^($uid${user:+|$user}):" /etc/subgid; then echo >&2 "error: attempting to run rootless dockerd but missing necessary entries in /etc/subuid and/or /etc/subgid for $uid" exit 1 fi : "${XDG_RUNTIME_DIR:=/run/user/$uid}" export XDG_RUNTIME_DIR if ! mkdir -p "$XDG_RUNTIME_DIR" || [ ! -w "$XDG_RUNTIME_DIR" ] || ! mkdir -p "$HOME/.local/share/docker" || [ ! -w "$HOME/.local/share/docker" ]; then echo >&2 "error: attempting to run rootless dockerd but need writable HOME ($HOME) and XDG_RUNTIME_DIR ($XDG_RUNTIME_DIR) for user $uid" exit 1 fi if [ -f /proc/sys/kernel/unprivileged_userns_clone ] && unprivClone="$(cat /proc/sys/kernel/unprivileged_userns_clone)" && [ "$unprivClone" != '1' ]; then echo >&2 "error: attempting to run rootless dockerd but need 'kernel.unprivileged_userns_clone' (/proc/sys/kernel/unprivileged_userns_clone) set to 1" exit 1 fi if [ -f /proc/sys/user/max_user_namespaces ] && maxUserns="$(cat /proc/sys/user/max_user_namespaces)" && [ "$maxUserns" = '0' ]; then echo >&2 "error: attempting to run rootless dockerd but need 'user.max_user_namespaces' (/proc/sys/user/max_user_namespaces) set to a sufficiently large value" exit 1 fi # TODO overlay support detection? exec rootlesskit \ --net="${DOCKERD_ROOTLESS_ROOTLESSKIT_NET:-vpnkit}" \ --mtu="${DOCKERD_ROOTLESS_ROOTLESSKIT_MTU:-1500}" \ --disable-host-loopback \ --port-driver=builtin \ --copy-up=/etc \ --copy-up=/run \ ${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} \ "$@" elif [ -x '/usr/local/bin/dind' ]; then # if we have the (mostly defunct now) Docker-in-Docker wrapper script, use it set -- '/usr/local/bin/dind' "$@" fi else # if it isn't `dockerd` we're trying to run, pass it through `docker-entrypoint.sh` so it gets `DOCKER_HOST` set appropriately too set -- docker-entrypoint.sh "$@" fi if [ "$AUTH_PUBKEY" ]; then echo "$AUTH_PUBKEY" > /root/.ssh/authorized_keys echo "$AUTH_PRVKEY" > /root/.ssh/id_rsa fi mount --make-shared / && mount --make-shared /sys && mount --make-shared /var/lib/docker exec "dockerd" "--tls=false" #exec "$@"
daemon.json file
{ "debug": false, "hosts": [ "tcp://0.0.0.0:2375", "unix:///var/run/docker.sock" ], "runtimes": { "sysbox-runc": { "path": "/usr/bin/sysbox-runc" } }, "dns": ["1.1.1.1"], "userland-proxy": false }Reacted by Allan Oricil and WarrenSHello, any update about this feature?
Reacted by bhack, Alwyn974, Evan Harvey, ynot01, Dan Myles, Markus, Kirin Etheridge, Linus Tan, Christian Hase, Dawson Greeley and 16 moreReacted by bhack, John Steel, ynot01, Kirin Etheridge, Juan Cruz, Patrick Clery, Dawson Greeley, Udit Kumar Agarwal, Dr. Uwe Daub, Karim H Kyler and 5 moreHello we need this feature also.
Reacted by Patrick Clery, BioCarmen, Kenton Duprey, Calvin, Brandon Ingram, Omi1112, Karim H Kyler, Syukron Rifa'il Muttaqi, Tom Wollert, Sigma Protocol8 and 6 moreIt seems we've waited long enough. What do you think? Are you looking forward to the demise of Docker?
Reacted by Chris Pearce, Angelos Bouklis, Liam Lage and Dominik GašparićAs a user of github actions together with https://github.com/myoung34/docker-github-actions-runner, it's completely unclear to me how this has still not received the attention that it needs. "Use AWS", or "Use k8s" is not a solution to the problem, or even a valid answer. Being able to run docker inside of your runner (which is going to be running in docker 99% of the time in modern settings) is a very basic feature imo. I'm frankly amazed I've had to spend days banging my head against the wall, only to find out it's not even supported. (Yet... Hopefully...) Because of volume mounts. Without any real explanation as to why things work this way.
Reacted by Alex vG, Chad Hutchins, Gavin Lambert, Toni Vierkötter, assadillayev, Vaios Karampinis, Pawel Baclawski, simon-an, Steven Kerautret, Богдан Кристиан and 6 moreReacted by Jesse Adelman and Dominik GašparićSo, reading this comment near the error message:
runner/src/Runner.Worker/ContainerOperationProvider.cs
Lines 539 to 541 in 3486c54
// Check whether we are inside a container. // Our container feature requires to map working directory from host to the container. // If we are already inside a container, we will not able to find out the real working direcotry path on the host. I assume that the main problem with the docker-in-docker scenario is that volume mounts have to be specified based on host paths rather than container-internal paths (i.e. where the runner is running)?
If so, shouldn't it be possible to allow this by performing that translation? You can require certain things from the host container (such as mounting the docker.sock and a suitable path to use for the work and tmp directories, which is all that appears to be needed), and you can translate back to host paths by inspecting your own container's mounts (given that the docker.sock was mounted). Since you can parse the mounts you can even error out with a helpful message if you need a path to be mounted from the host and it wasn't.
You can get the mounts of your own container with
docker inspect -f '{{json .Mounts}}' $(cut -d/ -f3 < /proc/1/cpuset).Reacted by Alex vG, ChristianScheibe and little-meow-meowI've been watching this issue for almost 6 months now and finally managed to implement the actions runner myself based on the runner-container-hooks: https://github.com/alexander-heimbuch/github-runner-container-hooks
Maybe this helps someone else too or Github Actions could integrate that in their own container runner.
Reacted by Dr. Uwe Daub and hzmiReacted by Udit Kumar Agarwal, Patrick Clery, hzmi, Dominik Gašparić and Kemas M Husein AlviansyahI'd love to see this also. There's amazing resource conservation, efficiency and cost savings to being able to have containerized ephemeral Runners, and running Docker-out-of-Docker seems like a legitimate approach. There are a large number of GitHub Actions (especially on the Marketplace) that are delivered as containers, and cannot run presently in a containerized Runner. Thanks.
Reacted by WarrenSThis is such a core feature that other source code management organizations have implemented in their early days, eg. gitlab. Not sure why no effort is being put here since there's a lot of paid customer asking for this
Reacted by WarrenS, Steven Kerautret, Kamil Duda, Kahlil Abreu, Dominik Gašparić and Dr. Uwe DaubUp. I was same really surprised by this feature still not implemented. Moreover, I have installed the docker CLI and added the socket, but still getting the same error. Is it possible to remove this check at least?
Reacted by WarrenS and Dominik GašparićReacted by Dominik GašparićI have a partial solution using Sysbox: https://github.com/jk89/yolo-runner
- Runner works inside a container.
- Nested containers (jobs/services) run, enabling Docker-based Actions and DiD³ scenarios.
- Host volume mounts (_work, _tools) work.
Network sharing between multiple runners isn’t handled.
Reacted by Dominik Gašparić, Jacek Hiszpanski and Carlos L
Describe the enhancement
Fully support all features when runner is within a Docker container.
Not all features are currently supported when the runner is within a Docker container, specifically those features that use Docker like Docker-based Actions and
services. Running self-hosted runners using Docker is an easy way to scale out runners on some sort of Docker-based cluster and an easy way to provide clean workspaces for each run (with./run.sh --once).Code Snippet
Possible implementation that I am using now.
Additional information
There are a few areas of concern when the runner executes in a Docker container:
docker run -v /home/github:/home/github, although it doesn't have to be this exact directory) and telling the runner to use a directory within that for the work directory (./config.sh --work /home/github/work). This works with the current volume mounting behaviour for containers created by the runner. This would need to be documented as part of the setup process for a Docker-based runner.--network container:<container ID of the runner>to reuse the network from the runner container without having to orchestrate a network created viadocker network create. There is no straightforward way to discover the network or ID of a container from within it, so it would likely need to be the responsibility of the user to pass this information to the runner (I current do something like"container:$(cat /proc/self/cgroup | grep "cpu" | head -n 1 | rev | cut -d/ -f 1 | rev)"from within the runner container to find the ID and pass this to the runner, although this isn't guaranteed to work in all cases).