无法使用Go客户端从Docker到达stdout

我有一个小项目,我的服务器将http发送的C文件复制到Docker容器中,在那里编译和运行它们.
但是,我无法获取任何数据发送到容器中的stdout.

我已确定将文件发送到Docker容器中,还有更多 – 编译的任何问题都显示在错误流中.但是,在C程序中通过stderr发送数据也没有显示任何结果,直到我使用Dockerfile,使用’>& 2 echo“”’以某种方式将数据推送到流中并且我能够读取它.

现在,如上所述,我只能阅读stderr,完全归功于一种解决方法.知道为什么我不能使用标准方法吗?

去服务器

package main

import (
    "fmt"
    "net/http"
    "io"
    "os"
    "os/exec"
    "log"
    "encoding/json"

    "github.com/docker/docker/client"
    dockertypes "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    "golang.org/x/net/context"
    "time"
    "bytes"
)

type Result struct {
    CompilationCode int
    RunCode int
    TestsPositive int
    TestsTotal int
}

func upload(w http.ResponseWriter,r *http.Request) {
    log.Println("method:",r.Method)
    if r.Method == "POST" {
        log.Println("Processing new SUBMISSION.")
        // https://github.com/astaxie/build-web-application-with-golang/blob/master/de/04.5.md
        r.ParseMultipartForm(32 << 20)
        file,handler,err := r.FormFile("file")
        if err != nil {
            fmt.Println(err)
            return
        }

        defer file.Close()
        baseName:= os.Args[1]
        f,err := os.OpenFile(baseName+handler.Filename,os.O_WRONLY|os.O_CREATE,777)
        if err != nil {
            fmt.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f,file)
        if err != nil {
            fmt.Println(err)
            return
        }

        compilationCode,runCode,testsPositive,testsTotal := processWithDocker(baseName + handler.Filename,handler.Filename)

        result := Result{
            CompilationCode: compilationCode,RunCode: runCode,TestsPositive:testsPositive,TestsTotal:testsTotal,}
        resultMarshaled,_ := json.Marshal(result)
        w.Write(resultMarshaled)
    } else {
        w.Write([]byte("GO server is active. Use POST to submit your solution."))
    }
}

// there is assumption that docker is installed where server.go is running
// and the container is already pulled
// TODO: handle situation when container is not pulled
// TODO: somehow capture if compilation wasn't successful and
// TODO: distinguish it from possible execution / time limit / memory limit error
// https://stackoverflow.com/questions/18986943/in-golang-how-can-i-write-the-stdout-of-an-exec-cmd-to-a-file

func processWithDocker(filenameWithDir string,filenameWithoutDir string) (int,int,int) {

    ctx,cancel := context.WithTimeout(context.Background(),10*time.Second)
    defer cancel()
    cli,err := client.NewEnvClient()
    if err != nil {
        panic(err)
    }

    var hostVolumeString = filenameWithDir
    var hostConfigBindString = hostVolumeString  + ":/WORKING_FOLDER/" + filenameWithoutDir

    var hostConfig = &container.HostConfig{
        Binds: []string{hostConfigBindString},}

    resp,err := cli.ContainerCreate(ctx,&container.Config{
        Image: "tusty53/ubuntu_c_runner:twelfth",Env: []string{"F00=" + filenameWithoutDir},Volumes: map[string]struct{}{
            hostVolumeString: struct{}{},},hostConfig,nil,"")
    if err != nil {
        panic(err)
    }

    if err := cli.ContainerStart(ctx,resp.ID,dockertypes.ContainerStartOptions{}); err != nil {
        panic(err)
    }

    fmt.Println(resp.ID)

    var exited = false

    for !exited {

        json,err := cli.ContainerInspect(ctx,resp.ID)
        if err != nil {
            panic(err)
        }

        exited = json.State.Running

        fmt.Println(json.State.Status)
    }

    normalOut,err := cli.ContainerLogs(ctx,dockertypes.ContainerLogsOptions{ShowStdout: true,ShowStderr: false})
    if err != nil {
        panic(err)
    }

    errorOut,dockertypes.ContainerLogsOptions{ShowStdout: false,ShowStderr: true})
    if err != nil {
        panic(err)
    }

    buf := new(bytes.Buffer)
    buf.ReadFrom(normalOut)
    sOut := buf.String()

    buf2 := new(bytes.Buffer)
    buf2.ReadFrom(errorOut)
    sErr := buf2.String()

    log.Printf("start\n")
    log.Printf(sOut)
    log.Printf("end\n")

    log.Printf("start error\n")
    log.Printf(sErr)
    log.Printf("end error\n")


    var testsPositive=0
    var testsTotal=0

    if(sErr!=""){
        return 0,0
    }

    if(sOut!=""){
        fmt.Sscanf(sOut,"%d %d",&testsPositive,&testsTotal)
        return 1,1,testsTotal
    }
    return 1,0

}


// Creates examine directory if it doesn't exist.
// If examine directory already exists,then comes an error.
func prepareDir() {
    cmdMkdir := exec.Command("mkdir",os.Args[1])
    errMkdir := cmdMkdir.Run()
    if errMkdir != nil {
        log.Println(errMkdir)
    }
}

func main() {
    prepareDir()
    go http.HandleFunc("/submission",upload)
    http.ListenAndServe(":8123",nil)
}

Dockerfile

FROM ubuntu
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
    apt-get -y install gcc
COPY . /WORKING_FOLDER
WORKDIR /WORKING_FOLDER
CMD ["./chain"] 

链文件

#!/bin/bash
gcc -Wall $F00  -o hello
./hello
>&2 echo ""
最佳答案
您应该考虑将Docker CLI作为一个单独的进程运行,只需读取其stdout和stderr,例如:

cmd := exec.Command("docker","run","-v=

相关文章

最近一直在开发Apworks框架的案例代码,同时也在一起修复Apw...
最近每天都在空闲时间努力编写Apworks框架的案例代码WeText。...
在《Kubernetes中分布式存储Rook-Ceph部署快速演练》文章中,...
最近在项目中有涉及到Kubernetes的分布式存储部分的内容,也...
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.ne...
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.ne...