美文网首页
3.从0实现Online Judge(go语言)-Docker相

3.从0实现Online Judge(go语言)-Docker相

作者: _codelover | 来源:发表于2019-05-19 12:27 被阅读0次

    源码见:https://github.com/lovercode/GO_OJ.git,demo见:https://codelover.me/run.html

    Docker相关

    compilerrunner都是运行在docker容器中,可以进行资源限制和隔离,主要的实现如下。

    初始化compiler容器

    主要是根据配置文件来启动多个compiler的容器

    func init() {
        for num := uint64(0); num < conf.GlobalConfig.CompilerNum; num++ {
            go initCompilerDocker(conf.GlobalConfig.CompilerDocker)
        }
    
    }
    
    func initCompilerDocker(Conf conf.DockerConfig) {
        ctx := context.Background()
        cli, err := client.NewClientWithOpts(client.WithVersion("1.18"))
        if err != nil {
            panic(err)
        }
    
        if err != nil {
            panic(err)
        }
        Config := container.Config{
            Image:      Conf.DockerName,
            Cmd:        Conf.Cmd,
            WorkingDir: Conf.WorkDir,
        }
        var mounts []mount.Mount
        for k, v := range Conf.DockerMount {
            mounts = append(mounts, mount.Mount{
                Type:   mount.TypeBind,
                Source: k,
                Target: v,
            })
        }
    
        HostConfig := container.HostConfig{
            Mounts: mounts,
            // Resources:      Resources,
            ReadonlyRootfs: Conf.ReadonlyRootfs,
            // Runtime:        "runsc",
        }
        if Conf.Memory >= 4194304 { //<4m设置无效
            Resources := container.Resources{
                Memory:    Conf.Memory,   //4m
                CPUQuota:  Conf.CpuQuota, //CPU资源的绝对限制,一般和CpuPeriod结合在一起,CpuQuota/CpuPeriod,就是能够使用的核数
                CPUPeriod: Conf.CpuPeriod,
            }
            HostConfig.Resources = Resources
        }
        resp, err := cli.ContainerCreate(ctx, &Config, &HostConfig, nil, "")
        defer cli.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
    
        if err != nil {
            panic(err)
        }
    
    tag:
        if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
            panic(err)
        }
    
        var res container.ContainerWaitOKBody
        statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
    
        select {
        case err := <-errCh:
            if err != nil {
                log.Println("编译机出错退出")
                goto end
            }
        case res = <-statusCh:
            if res.StatusCode != 0 {
    
            }
    
            log.Println("编译机退出,准备重启...")
            goto tag
        }
    end:
        log.Println("编译机退出...")
    
    }
    
    
    • 配置文件
    CompilerNum=1
    CompileDataPath="/home/codelover/go/src/go_oj/bin/run"
    [CompilerDocker]
        Memory=-1
        CpuQuota=100000
        CpuPeriod=100000
        DockerName = "compiler:v2"
        Cmd = ["/bin/sh", "-c", "./compiler"]
        WorkDir = "/compiler"
        [CompilerDocker.DockerMount]
            "/home/codelover/go/src/go_oj/bin" = "/compiler"
    

    初始化所有runner容器

    与初始化compiler一样,读取配置直接初始化

    
    func init() {
        for _, v := range conf.GlobalConfig.RunnerDocker {
            for num := 0; num < v.RunNum; num++ {
                go initRunnerDocker(v)
            }
        }
    }
    
    func initRunnerDocker(Conf conf.DockerConfig) {
        ctx := context.Background()
        cli, err := client.NewClientWithOpts(client.WithVersion("1.37"))
        if err != nil {
            panic(err)
        }
    
        if err != nil {
            panic(err)
        }
        Config := container.Config{
            Image:      Conf.DockerName,
            Cmd:        Conf.Cmd,
            WorkingDir: Conf.WorkDir,
        }
        var mounts []mount.Mount
        for k, v := range Conf.DockerMount {
            mounts = append(mounts, mount.Mount{
                Type:   mount.TypeBind,
                Source: k,
                Target: v,
                // ReadOnly: true,
            })
        }
        Init := true
        HostConfig := container.HostConfig{
            Mounts:         mounts,
            ReadonlyRootfs: Conf.ReadonlyRootfs,
            Init:           &Init,
            // Runtime:        "runsc",
        }
        if Conf.Memory >= 4194304 { //<4m设置无效
            Resources := container.Resources{
                Memory:    Conf.Memory,   //4m
                CPUQuota:  Conf.CpuQuota, //CPU资源的绝对限制,一般和CpuPeriod结合在一起,CpuQuota/CpuPeriod,就是能够使用的核数
                CPUPeriod: Conf.CpuPeriod,
            }
            HostConfig.Resources = Resources
        }
        resp, err := cli.ContainerCreate(ctx, &Config, &HostConfig, nil, "")
        defer cli.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
    
        if err != nil {
            panic(err)
        }
    
    tag:
        if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
            panic(err)
        }
    
        var res container.ContainerWaitOKBody
        statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
    
        select {
        case err := <-errCh:
            if err != nil {
                log.Println("运行机出错退出", err)
                goto end
            }
        case res = <-statusCh:
            if res.StatusCode != 0 {
    
            }
    
            log.Println("运行机退出,准备重启...", res)
            goto tag
        }
    end:
        log.Println("运行机退出...")
    
    
    }
    
    • 配置如下
    #c语言
    [RunnerDocker.1]
        RunNum=1
        Memory=419430400
        CpuQuota=50000
        CpuPeriod=100000
        ReadonlyRootfs=false
        DockerName="alpine_c:latest"
        Cmd = ["./runner","conf/runner_config_1.toml"]
        WorkDir = "/runner"
        [RunnerDocker.1.DockerMount]
            "/home/codelover/go/src/go_oj/bin" = "/runner"
    
    #php
    [RunnerDocker.5]
        RunNum=1
        Memory=-1
        CpuQuota=100000
        CpuPeriod=100000
        ReadonlyRootfs=false
        DockerName="alpine_php:latest"
        Cmd = ["./runner","conf/runner_config_5.toml"]
        WorkDir = "/runner"
        [RunnerDocker.5.DockerMount]
            "/home/codelover/go/src/go_oj/bin" = "/runner"
            
    

    dockerfile

    • 编译机需要有所有编译环境
    FROM frolvlad/alpine-glibc:latest
    RUN apk add --no-cache gcc &&\
        apk add --no-cache g++ &&\
        apk add --no-cache php &&\
        apk add --no-cache openjdk8 &&\
        apk add --no-cache pyflakes &&\
        apk add --no-cache go &&\
        apk add --no-cache libstdc++ 
    ENV PATH "$PATH:/usr/lib/jvm/default-jvm/bin"
        
    
    
    • 运行机dockerfile示例(php)
      user用于运行用户程序
    FROM frolvlad/alpine-glibc:latest
    RUN adduser -D user0 -G nogroup &&\
        adduser -D user1 -G nogroup &&\
        adduser -D user2 -G nogroup &&\
        adduser -D user3 -G nogroup &&\
        adduser -D user4 -G nogroup &&\
        adduser -D user5 -G nogroup &&\
        adduser -D user6 -G nogroup &&\
        adduser -D user7 -G nogroup &&\
        adduser -D user8 -G nogroup &&\
        adduser -D user9 -G nogroup &&\
        adduser -D user10 -G nogroup &&\
        apk add --no-cache php7 &&\
        apk add --no-cache libseccomp-dev
        
    
    

    相关文章

      网友评论

          本文标题:3.从0实现Online Judge(go语言)-Docker相

          本文链接:https://www.haomeiwen.com/subject/czwfzqtx.html