in sandbox/sandbox.go [434:522]
func startContainer(ctx context.Context) (c *Container, err error) {
start := time.Now()
defer func() {
status := "success"
if err != nil {
status = "error"
}
// Ignore error. The only error can be invalid tag key or value length, which we know are safe.
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(kContainerCreateSuccess, status)},
mContainerCreateLatency.M(float64(time.Since(start))/float64(time.Millisecond)))
}()
name := "play_run_" + randHex(8)
setContainerWanted(name, true)
cmd := exec.Command("docker", "run",
"--name="+name,
"--rm",
"--tmpfs=/tmpfs:exec",
"-i", // read stdin
"--runtime=runsc",
"--network=none",
"--memory="+fmt.Sprint(memoryLimitBytes),
*container,
"--mode=contained")
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, err
}
pr, pw := io.Pipe()
stdout := &limitedWriter{dst: &bytes.Buffer{}, n: maxOutputSize + int64(len(containedStartMessage))}
stderr := &limitedWriter{dst: &bytes.Buffer{}, n: maxOutputSize}
cmd.Stdout = &switchWriter{switchAfter: []byte(containedStartMessage), dst1: pw, dst2: stdout}
cmd.Stderr = stderr
if err := cmd.Start(); err != nil {
return nil, err
}
ctx, cancel := context.WithCancel(ctx)
c = &Container{
name: name,
stdin: stdin,
stdout: stdout,
stderr: stderr,
cmd: cmd,
cancelCmd: cancel,
waitErr: make(chan error, 1),
}
go func() {
c.waitErr <- internal.WaitOrStop(ctx, cmd, os.Interrupt, 250*time.Millisecond)
}()
defer func() {
if err != nil {
c.Close()
}
}()
startErr := make(chan error, 1)
go func() {
buf := make([]byte, len(containedStartMessage))
_, err := io.ReadFull(pr, buf)
if err != nil {
startErr <- fmt.Errorf("error reading header from sandbox container: %v", err)
} else if string(buf) != containedStartMessage {
startErr <- fmt.Errorf("sandbox container sent wrong header %q; want %q", buf, containedStartMessage)
} else {
startErr <- nil
}
}()
timer := time.NewTimer(startTimeout)
defer timer.Stop()
select {
case <-timer.C:
err := fmt.Errorf("timeout starting container %q", name)
cancel()
<-startErr
return nil, err
case err := <-startErr:
if err != nil {
return nil, err
}
}
log.Printf("started container %q", name)
return c, nil
}