Go-runc example?
pwFoo opened this issue · 5 comments
Hi,
I'm new with Go, so it will be a stupid question... Sorry.
Could you provide a simple example how to run a container with go-runc?
Thanks!
I think go-runc is not so independent project to run container, may it is more suit to work with containerd, just my thought.
I don't know if i'll have time to turn this into docs, but some code I was playing with looks like:
package run
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
runc "github.com/containerd/go-runc"
libpull "github.com/svendowideit/cirri/lib/pull"
"github.com/svendowideit/cirri/options"
"github.com/opencontainers/runc/libcontainer/specconv"
"github.com/opencontainers/runtime-spec/specs-go"
//"github.com/opencontainers/runtime-spec/specs-go"
)
func Run(image string) error {
rootfsPath := options.GetImageRootfsDir(image)
if _, err := os.Stat(rootfsPath); os.IsNotExist(err) {
// pulls an image from a registry, and unpacks the layers into a rootfs
if err = libpull.Pull(image); err != nil {
return err
}
}
// TODO: name should be generated? plus aliases?
name := image
bundleDir := filepath.Join(options.LocalCacheDir(), "containers", name)
if err := os.MkdirAll(bundleDir, 0775); err != nil {
return err
}
if err := os.Chdir(bundleDir); err != nil {
return err
}
configJson := "config.json"
if _, err := os.Stat(configJson); os.IsNotExist(err) {
spec := specconv.Example()
specconv.ToRootless(spec)
// TODO: should also use the info in the manifest to determine default command/entrypoint etc
spec.Root.Path = rootfsPath
//if err := injectPRoot(spec); err != nil {
//return err
//}
//save it..
data, err := json.MarshalIndent(spec, "", "\t")
if err != nil {
return err
}
err = ioutil.WriteFile(configJson, data, 0666)
if err != nil {
return err
}
}
cfg := &runc.Runc{
//Command: "/home/sven/go/bin/runc",
Root: options.GetRuncDir(),
Debug: true,
//Rootless: false,
}
io, err := runc.NewSTDIO()
if err != nil {
fmt.Printf("ERROR: %s\n", err)
}
status, err := cfg.Run(context.Background(), "test", ".", &runc.CreateOpts{
IO: io,
})
if err == nil {
// exit with the container's exit status so any external supervisor is
// notified of the exit with the correct exit status.
fmt.Printf("Status == %d\n", status)
os.Exit(status)
}
fmt.Printf("ERROR: %s", err)
return nil
}
@estesp ^^^ is the kind of example that I'm talking about - I'm sure that I'm not using the library "in the right way" but the only way consumers of a library will know what was intended, is for those that wrote it to give working examples.
@SvenDowideit Am I understanding correctly that your example would not have a need for an actual runc binary to be installed on a system, or am I seeing this wrong?
I've been trying to use a couple of things in the container world "as a library (package)" and having finally made containerd to work in this way, I noticed that the moment I do not have runc installed I get the following error:
INFO[2021-11-15T00:05:39.074495020+01:00] containerd successfully booted in 0.035576s
2021/11/15 00:05:44 Successfully pulled docker.io/theapemachine/term:latest image
2021/11/15 00:05:44 start failed: runtime "io.containerd.runc.v2" binary not installed "containerd-shim-runc-v2": file does not exist: unknown
I was writing a tool for a previous employer that would use whatever container tooling was installed - in this example, its using an existing runc
binary (as that's what go-run
's intent is)
its been a long time since i sighted that experiment - but I think I did end up adding some other runc based code only path - but this isn't it.