Virutal machine runner #316

Open
opened 2023-08-01 19:58:52 +00:00 by Ghost · 3 comments
Ghost commented 2023-08-01 19:58:52 +00:00 (Migrated from gitea.com)

I'd like an option to run full VM per job.

It should work similarly to container version, which it's own vm section in config.yaml.

Some options I was thinking about:

This will require some modification in act and probably in upstream instead of the fork. But for now I want to get some other inputs on this.

I'd like an option to run full VM per job. It should work similarly to container version, which it's own `vm` section in `config.yaml`. Some options I was thinking about: - libvirt based - [digital ocean has go bindings for libvirt](https://github.com/digitalocean/go-libvirt) - qemu based - [digital ocean also made some](https://github.com/digitalocean/go-qemu) - vagrant - this seems like the best choice in my opinion. Gitea already has vagrant package registry so that's a plus. Hashicorp is porting vagrant to Go, so there is a chance for a normal library to be made (or at least not a wrapper around ruby). So far, there are only wrappers around the program [which aren't really maintained](https://github.com/bmatcuk/go-vagrant). This will require some modification in act and probably in upstream instead of the fork. But for now I want to get some other inputs on this.
Ghost commented 2023-08-06 13:33:20 +00:00 (Migrated from gitea.com)

I found that there are official libvirt bindings: https://pkg.go.dev/libvirt.org/go/libvirt

So here's my proposal for a PoC implementation.

  1. The runner would connect to either a system or session URI and search for VMs with the name from label, so given upstream:vm:local label it would look for machine named local.
  2. When the vm runner is requested, it clones the vm so the changes aren't affecting the base vm. After full run ends the clone is deleted.

No idea how to actually run a workflow on the vm yet.

Benefits of this approach:

  • We don't touch base image
  • If for any reason one wants to update the base image, it can be done with recreating the resource, swapping disks, booting the image and updating it.
  • Since libvirt has couple drivers available, implementing lxc runner should be easier.
  • It maybe will work out-of-the-box on windows and mac?

Downsides:

  • The VM needs to be preconfigured.
  • Potential collision of labels? No idea how the syntax runs-on: example should be handled if someone would have both example:docker://node and example:vm:node. Technically should launch either container or vm.
  • The VM clone will take up some space temporarily.
I found that there are official libvirt bindings: https://pkg.go.dev/libvirt.org/go/libvirt So here's my proposal for a PoC implementation. 1. The runner would connect to either a system or session URI and search for VMs with the name from label, so given `upstream:vm:local` label it would look for machine named `local`. 2. When the vm runner is requested, it clones the vm so the changes aren't affecting the base vm. After full run ends the clone is deleted. No idea how to actually run a workflow on the vm yet. Benefits of this approach: - We don't touch base image - If for any reason one wants to update the base image, it can be done with recreating the resource, swapping disks, booting the image and updating it. - Since libvirt has [couple drivers available](https://libvirt.org/drivers.html), implementing lxc runner should be easier. - It maybe will work out-of-the-box on windows and mac? Downsides: - The VM needs to be preconfigured. - Potential collision of labels? No idea how the syntax `runs-on: example` should be handled if someone would have both `example:docker://node` and `example:vm:node`. Technically should launch either container or vm. - The VM clone will take up some space temporarily.
brthor commented 2023-12-06 20:41:45 +00:00 (Migrated from gitea.com)

For somewhat niche use-cases this feature will be very useful.

Here is an example that works on github actions but not gitea.

  • I have a specific Dockerfile that provides an environment for building a part of the codebase

  • My build script mounts the code directory inside so the output will be present after the container finishes.

  • The rest of the build/deployment proceeds using the outputs of the first part.

  • On gitea, the code directory cannot be mounted inside the second container.

    • The executor image (the target of 'runs_on') exists inside a docker container itself.
    • Mounting a directory from container to container does not seem to work.
  • If the executor (the target of 'runs_on') were a VM, all of the actions and build code can operate as if it were on a non-docker host.

Vagrant

I have no experience with this codebase but I currently use vagrant to run the act_runner itself.

Supporting vagrant has the following benefits IMO:

  • A well-defined file format similar to docker in which VM definitions can be created and maintained.
  • The ability to pre-provision boxes and then launch them with independent filesystems (I believe).
  • A pre-existing cloud platform where commonly used boxes (like ubuntu-22.04) can be stored and downloaded.

Discussion

Regarding some points you made above:

The VM needs to be preconfigured.

The same is true for docker, this is only invisible because the commonly used boxes are already on dockerhub.

Potential collision of labels?

This is an issue that should be handled by the administrator of the runner, and cause an error at startup.

For somewhat niche use-cases this feature will be very useful. Here is an example that **works on github actions** but not gitea. - I have a specific Dockerfile that provides an environment for building a part of the codebase - My build script mounts the code directory inside so the output will be present after the container finishes. - The rest of the build/deployment proceeds using the outputs of the first part. - On gitea, the code directory cannot be mounted inside the second container. - The executor image (the target of 'runs_on') exists inside a docker container itself. - Mounting a directory from container to container does not seem to work. - If the executor (the target of 'runs_on') were a VM, all of the actions and build code can operate as if it were on a non-docker host. ### Vagrant I have no experience with this codebase but I currently use vagrant to run the act_runner itself. Supporting vagrant has the following benefits IMO: - A well-defined file format similar to docker in which VM definitions can be created and maintained. - The ability to pre-provision boxes and then launch them with independent filesystems (I believe). - A pre-existing cloud platform where commonly used boxes (like ubuntu-22.04) can be stored and downloaded. ### Discussion Regarding some points you made above: > The VM needs to be preconfigured. The same is true for docker, this is only invisible because the commonly used boxes are already on dockerhub. > Potential collision of labels? This is an issue that should be handled by the administrator of the runner, and cause an error at startup.
Ghost commented 2023-12-26 23:06:54 +00:00 (Migrated from gitea.com)

I think I found a good solution for the management of the images and instances. https://linuxcontainers.org/incus/introduction/
Afaik it's a fork of LXD so it also might be able to do this. It can handle both VMs and lxc containers so I think it's a potentially good solution. I need to look more into it though but it seems promising.

Vagrant

Initially I suggested it because of 2 things:

  • Gitea registry for vagrant images exists
  • Vagrant was getting a rewrite in golang which would make it easier to potentially integrate it.

I still think it's a decent idea... no idea how to integrate it though. And there's also the license switch they did.

Discussion

The VM needs to be preconfigured.

The same is true for docker, this is only invisible because the commonly used boxes are already on dockerhub.

True. In retrospect I can't exactly point out why I made this a big deal. It's not the runners job to make sure the environments are the same.

Potential collision of labels?

This is an issue that should be handled by the administrator of the runner, and cause an error at startup.

I'd opt for running it anyway just picking a random backend.

runs-on: ["node"] - should schedule a job on any backend
runs-on: ["node","docker"] - should schedule a job on docker backend

Though I'm open for a debate/alternatives on this.
One option is to use the group instead of labels for backends.

I think I found a good solution for the management of the images and instances. https://linuxcontainers.org/incus/introduction/ Afaik it's a fork of LXD so it also might be able to do this. It can handle both VMs and lxc containers so I think it's a potentially good solution. I need to look more into it though but it seems promising. ## Vagrant Initially I suggested it because of 2 things: - Gitea registry for vagrant images exists - Vagrant was getting a rewrite in golang which would make it easier to potentially integrate it. I still think it's a decent idea... no idea how to integrate it though. And there's also the license switch they did. ## Discussion > > The VM needs to be preconfigured. > > The same is true for docker, this is only invisible because the commonly used boxes are already on dockerhub. True. In retrospect I can't exactly point out why I made this a big deal. It's not the runners job to make sure the environments are the same. > > Potential collision of labels? > > This is an issue that should be handled by the administrator of the runner, and cause an error at startup. I'd opt for running it anyway just picking a random backend. `runs-on: ["node"]` - should schedule a job on any backend `runs-on: ["node","docker"]` - should schedule a job on docker backend Though I'm open for a debate/alternatives on this. One option is to use the `group` instead of labels for backends.
Sign in to join this conversation.