-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Add firecracker init logic to connector-init
#890
Open
jshearer
wants to merge
17
commits into
master
Choose a base branch
from
feature/new_task_runtime
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jshearer
force-pushed
the
feature/new_task_runtime
branch
from
February 1, 2023 17:50
ce00215
to
b1ebf2b
Compare
…ocker image, using `connector-init` as the init
jshearer
force-pushed
the
feature/new_task_runtime
branch
from
February 6, 2023 15:55
88d7cbb
to
b8a68ec
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Introduce support for running tasks (currently captures and materializations, but also derivations in the future) in Firecracker, and wire up
flowctl-go
to be able to use it, currently gated behind a hard-coded flag because we can't run this in prod yet.Outside the VM
Firecracker is a virtual machine manager designed for Linux, so fundamentally the two things you need to run a VM are a kernel, and a userspace.
Kernel
The kernel is provided in a bundled
vmlinux.bin
file, which is the output of the kernel build process. I've included a fairly recent kernel build in theassets/
folder, as well as a config file that can be passed to https://github.com/anyfiddle/firecracker-kernel-builder in order to build it from scratch.Filesystems
We mount two filesystems to the VM: the root filesystem which contains the init program and any config needed, and the main filesystem which contains the unpacked image that contains the connector entrypoint and anything else it expects to exist.
At the moment, we use the equivalent of the following command to generate a tar file of the specified image:
We then use
virt-make-fs
to turn that tar file into an ext4-formatted binary file which we can pass to Firecracker as a mountable disk. This is a fairly wasteful process, especially if we start many VMs from the same image, or even images that share many of their layers. In the future we should runcontainerd
and use its ability to checkout/"lease" filesystems based on a set of layers. I left this out of scope for the initial work as it's mainly a performance optimization.Networking
Firecracker deals with networking by attaching to (or creating) a virtual TUN/TAP network device on the host, which acts as a mirror to/from
eth0
inside the guest. We have a few goals for guest networking:connector-init
exposesconnector-init
.We decided to leverage the existing world of CNI plugins in order to configure the networking here, as not only does it allow for clear and powerful configuration of NAT, firewall, IP address allocation, and port mapping, it also supports easy cleanup when a VM is to be shut down. As an additional layer, all networking config is done inside of a network namespace which is torn down once the VM exits.
Inside the VM
Part of a regular Linux userspace is the init program which is responsible for setting up things like special mounts, and then executing the actual entrypoint.
As it turns out,
connector-init
was already written with this purpose in mind: it exposes a GRPC API to invoke the real connector entrypoint, stream back its output, etc. So, in order to use it as the init program for our Firecracker VM, I needed to teach it about all of the linux booting stuff that a regular init would do:/dev
,/proc
,/sys
flow-firecracker
In order to coordinate all of the mentioned setup and teardown, I wrote the
flow-firecracker
binary which is responsible for taking a (Docker) image name as well as things like kernel, init program etc, and running it all inside of a Firecracker VM, as well as tearing it all down.flowctl-go
The first "real" use-case to test firecracker end-to-end is using it instead of Docker to run capture/materialization connectors; derivations require more integration work and will come later. In order to support this, there is now
runInFirecracker
ingo/connector/driver.go
that can be switched when you want to test running in firecracker.Hacks/Future work
firec
The best Rust crate to drive Firecracker is
firec
, and it's... pretty bad. Still worth using, but a bunch of features are left un-implemented, and rather than watching the socket to figure out when firecracker is running, it just... waits 10s. 🤦 I've had to forkfirec
to make a few critical things work, too.Despite Firecracker being written in Rust, the canonical client library is written in Go: https://github.com/firecracker-microvm/firecracker-go-sdk. Ideally we'd write a corresponding Rust client library and publish it.
cnitool
Very similar situation to above. CNI specifies that plugins are just binaries that take env vars/stdin and output stdout. That being said, there is a good bit of "client" magic that goes into invoking them, and shocker of shockers it's all written in Go. Fortunately they offer a binary called
cnitool
which does what we need so in this PR I just shell out to that, but in the future it would be super neat to have a useful CNI client library in Rust.Firecracker Requirements:
/opt/cni/bin
build_linux.sh
ptp
host-local
firewall
tc-redirect-tap
cnitool
binary on pathfirecracker
andjailer
binaries on pathvirt-make-fs
on pathNote: This will go away when we switch to using
containerd
libguestfs
. On Ubuntu:sudo apt-get install libguestfs-tools
mount
needs root.CAP_NET_ADMIN
jailer
needs all sorts of permissions involving cgroups, network namespaces, mounts etcfirecracker
needs to call/dev/kvm
This change is