containerd / go-runc

runc bindings for Go
Apache License 2.0
161 stars 71 forks source link

Go-runc example? #33

Open pwFoo opened 6 years ago

pwFoo commented 6 years ago

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!

Ace-Tang commented 5 years ago

I think go-runc is not so independent project to run container, may it is more suit to work with containerd, just my thought.

SvenDowideit commented 4 years ago

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
}
SvenDowideit commented 4 years ago

@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.

TheApeMachine commented 2 years ago

@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
SvenDowideit commented 2 years ago

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.