Problems: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error running createRuntime hook #0: exec: no command #4337
-
Hello everyone! I'm trying to use the
I used the following code to create a container via an package main
import (
"net/http"
"github.com/containerd/nerdctl/v2/pkg/clientutil"
"github.com/gin-gonic/gin"
"github.com/containerd/nerdctl/v2/pkg/api/types"
nerdctl "github.com/containerd/nerdctl/v2/pkg/cmd/container"
"github.com/containerd/nerdctl/v2/pkg/containerutil"
)
type FunctionCreateRequest struct {
ImageRef string `json:"image_ref"`
Labels FunctionCreateLabels `json:"labels"`
InRun bool `json:"in_run"`
}
type FunctionCreateLabels struct {
AppName string `json:"app.name"`
AppPort string `json:"app.port"`
AppVersion string `json:"app.version"`
}
type FunctionCreateResponse struct {
ContainerID string `json:"container_id"`
}
func FunctionCreate(c *gin.Context) {
var req FunctionCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
globalOpt := GetGlobalOptions()
// create container options
createOpt := types.ContainerCreateOptions{
GOptions: globalOpt,
Name: req.Labels.AppName,
Label: []string{
"app.name=" + req.Labels.AppName,
"app.port=" + req.Labels.AppPort,
"app.version=" + req.Labels.AppVersion,
},
Cgroupns: "host",
InRun: req.InRun,
Rm: true,
Pull: "missing", // always, missing, never
LogDriver: "json-file",
StopSignal: "SIGTERM",
Restart: "unless-stopped", // no, always, on-failure, unless-stopped
// GPUs: []string{"all"},
}
// create client
client, ctx, cancel, err := clientutil.NewClient(c.Request.Context(), globalOpt.Namespace, globalOpt.Address)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer cancel()
// create network manager
networkManager, err := containerutil.NewNetworkingOptionsManager(createOpt.GOptions, types.NetworkOptions{}, client)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// create container
container, _, err := nerdctl.Create(ctx, client, []string{req.ImageRef}, networkManager, createOpt)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, FunctionCreateResponse{
ContainerID: container.ID(),
})
} Run script:
And receive error:
my
Using curl to create the container works, but starting the container results in an error:
I'd like to understand the reasons behind these issues. Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
I want to use |
Beta Was this translation helpful? Give feedback.
-
@xgzlucario if you want to debug this, you should really consider simplifying, and building / isolating small pieces that work... So: are you able to write a simple cli that just starts a hard-coded container? (without any of the gingonic wrapping) Anyhow, your first problem is probably that you are missing in your main: Here is a working example: package main
import (
"context"
"encoding/json"
"fmt"
"github.com/containerd/nerdctl/v2/pkg/api/types"
"github.com/containerd/nerdctl/v2/pkg/clientutil"
nerdctl "github.com/containerd/nerdctl/v2/pkg/cmd/container"
"github.com/containerd/nerdctl/v2/pkg/config"
"github.com/containerd/nerdctl/v2/pkg/containerutil"
"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
"os"
)
func main() {
globalOpt := types.GlobalCommandOptions(*config.New())
rootlessutil.ParentMain(globalOpt.HostGatewayIP)
f, _ := json.MarshalIndent(globalOpt, "", " ")
fmt.Printf("%s\n", f)
// create container options
createOpt := types.ContainerCreateOptions{
GOptions: globalOpt,
Name: "foo",
Label: []string{},
Cgroupns: "host",
InRun: true,
Rm: false,
Pull: "missing",
LogDriver: "json-file",
StopSignal: "SIGTERM",
Restart: "unless-stopped",
}
// create client
client, ctx, cancel, err := clientutil.NewClient(context.Background(), globalOpt.Namespace, globalOpt.Address)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer cancel()
// create network manager
networkManager, err := containerutil.NewNetworkingOptionsManager(createOpt.GOptions, types.NetworkOptions{}, client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// create container
container, _, err := nerdctl.Create(ctx, client, []string{"debian"}, networkManager, createOpt)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cc, _ := json.MarshalIndent(container, "", " ")
fmt.Println(cc)
return
} For your second problem, the answer is very likely inside your Dockerfile - and the logs tell you what's wrong: -> "/usr/bin/gateway: no such file or directory" <- |
Beta Was this translation helpful? Give feedback.
-
I think here is the real problem, but i don't know how to fix it: package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/containerd/console"
"github.com/containerd/log"
"github.com/containerd/nerdctl/v2/pkg/api/types"
"github.com/containerd/nerdctl/v2/pkg/clientutil"
nerdctl "github.com/containerd/nerdctl/v2/pkg/cmd/container"
"github.com/containerd/nerdctl/v2/pkg/config"
"github.com/containerd/nerdctl/v2/pkg/containerutil"
"github.com/containerd/nerdctl/v2/pkg/labels"
"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
"github.com/containerd/nerdctl/v2/pkg/taskutil"
)
func main() {
globalOpt := types.GlobalCommandOptions(*config.New())
rootlessutil.ParentMain(globalOpt.HostGatewayIP)
f, _ := json.MarshalIndent(globalOpt, "", " ")
fmt.Printf("%s\n", f)
// create container options
createOpt := types.ContainerCreateOptions{
GOptions: globalOpt,
Name: "foo",
Label: []string{},
Cgroupns: "host",
InRun: true,
Detach: true,
Rm: false,
Pull: "missing",
LogDriver: "json-file",
StopSignal: "SIGTERM",
Restart: "no",
}
// create client
client, ctx, cancel, err := clientutil.NewClient(context.Background(), globalOpt.Namespace, globalOpt.Address)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer cancel()
// create network manager
networkManager, err := containerutil.NewNetworkingOptionsManager(createOpt.GOptions, types.NetworkOptions{}, client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// create container
c, _, err := nerdctl.Create(ctx, client, []string{"redis:alpine"}, networkManager, createOpt)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// copy from https://github.com/containerd/nerdctl/blob/87a6ab93ae4f3b3fe66e90eef61ed773b1881be7/cmd/nerdctl/container/container_run.go#L357
var con console.Console
lab, err := c.Labels(ctx)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
logURI := lab[labels.LogURI]
detachC := make(chan struct{})
task, err := taskutil.NewTask(ctx, client, c, createOpt.Attach, createOpt.Interactive, createOpt.TTY, createOpt.Detach,
con, logURI, createOpt.DetachKeys, createOpt.GOptions.Namespace, detachC)
if err != nil {
fmt.Println("ERROR 0")
fmt.Println(err)
os.Exit(1)
}
if err := task.Start(ctx); err != nil {
fmt.Println(err)
os.Exit(1)
}
if createOpt.Detach {
fmt.Fprintln(os.Stdout, c.ID())
return
}
statusC, err := task.Wait(ctx)
if err != nil {
fmt.Println("Container exit with error", err)
os.Exit(1)
}
select {
// io.Wait() would return when either 1) the user detaches from the container OR 2) the container is about to exit.
//
// If we replace the `select` block with io.Wait() and
// directly use task.Status() to check the status of the container after io.Wait() returns,
// it can still be running even though the container is about to exit (somehow especially for Windows).
//
// As a result, we need a separate detachC to distinguish from the 2 cases mentioned above.
case <-detachC:
io := task.IO()
if io == nil {
fmt.Println("got a nil IO from the task")
os.Exit(1)
}
io.Wait()
case status := <-statusC:
if createOpt.Rm {
if _, taskDeleteErr := task.Delete(ctx); taskDeleteErr != nil {
log.L.Error(taskDeleteErr)
}
}
code, _, err := status.Result()
if err != nil {
fmt.Println("Container exit with error", err)
os.Exit(1)
}
if code != 0 {
fmt.Println("Container exit with code", code)
}
}
} Output:
|
Beta Was this translation helpful? Give feedback.
-
Here is a full example for you that also start the container. Note that:
func main() {
// Implement logging
if len(os.Args) == 3 && os.Args[1] == logging.MagicArgv1 {
err := logging.Main(os.Args[2])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// Get options
globalOpt := types.GlobalCommandOptions(*config.New())
// Rootless
_ = rootlessutil.ParentMain(globalOpt.HostGatewayIP)
// Printout options for debug
f, _ := json.MarshalIndent(globalOpt, "", " ")
fmt.Printf("%s\n", f)
// Create container options
createOpt := types.ContainerCreateOptions{
GOptions: globalOpt,
// To be used by oci-hook
NerdctlCmd: "/usr/local/bin/nerdctl",
Name: "my-container",
Label: []string{},
Cgroupns: "private",
InRun: true,
Rm: false,
Pull: "missing",
LogDriver: "json-file",
StopSignal: "SIGTERM",
Restart: "unless-stopped",
Interactive: true,
}
// create client
client, ctx, cancel, err := clientutil.NewClient(context.Background(), globalOpt.Namespace, globalOpt.Address)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer cancel()
// create network manager
networkManager, err := containerutil.NewNetworkingOptionsManager(createOpt.GOptions, types.NetworkOptions{
NetworkSlice: []string{"bridge"},
}, client)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// create container
container, _, err := nerdctl.Create(ctx, client, []string{"debian"}, networkManager, createOpt)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = nerdctl.Start(ctx, client, []string{"my-container"}, types.ContainerStartOptions{
Attach: true,
Stdout: os.Stdout,
})
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cc, _ := json.MarshalIndent(container, "", " ")
fmt.Println(cc)
return
} |
Beta Was this translation helpful? Give feedback.
Here is a full example for you that also start the container.
Note that:
go run
this as the logging driver will point to the temporary binary built by go that would not last, so, you shouldgo build
then run your binarynerdctl
binary for oci-hooks (if you want to get rid of it, you have to implement that as well) (seeNerdctlCmd
)