dpnzf48660 2019-04-17 01:22
浏览 368

Golang Docker库-挂载主机目录卷

How do I perform the equivalent of:

docker run -v /host/path:/container/path image:tag

from Go using the official docker client package?

I've tried different Mounts and Volumes options within the HostOption and ConfigOption structs for the client.ContainerCreate() function, but can't quite figure it out.

In particular, the Volumes member (of type map[string]struct{}) is particularly hard to figure out how to use, and I can't find any documentation on what values are supposed to be present within the struct.

Code to demonstrate my problem:

package main

import (
    "context"
    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    //"github.com/docker/docker/api/types/mount"
    "github.com/docker/docker/client"
    "github.com/docker/docker/pkg/stdcopy"
    "log"
    "os"
    "path/filepath"
)

func getThisDir() string {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
        panic(err)
    }
    return dir
}

func main() {
    log.Println("Creating client")
    cli, err := client.NewClientWithOpts(client.FromEnv)
    if err != nil {
        panic(err)
    }

    image := "ubuntu:18.04"
    hostPath := getThisDir()
    containerPath := "/host_files"

    log.Printf("             Image: %s
", image)
    log.Printf("         Host Path: %s
", hostPath)
    log.Printf("    Container Path: %s
", containerPath)

    ctx := context.Background()
    cli.NegotiateAPIVersion(ctx)

    log.Println("Creating container")
    var cont container.ContainerCreateCreatedBody
    if cont, err = cli.ContainerCreate(
        context.Background(),
        &container.Config{
            Image:      image,
            Entrypoint: []string{"/bin/bash", "-c", "ls -la " + containerPath},
            Volumes: map[string]struct{}{
                hostPath: {},
            },
        },
        &container.HostConfig{
            Runtime: "runsc",
            /*
                Mounts: []mount.Mount{
                    mount.Mount{
                        Type:   mount.TypeVolume,
                        Source: hostPath,
                        Target: containerPath,
                    },
                },
            */
        },
        nil,
        "TEST_CONTAINER",
    ); err != nil {
        panic(err)
    }

    defer func() {
        log.Println("Cleaning up")
        if err := cli.ContainerRemove(
            context.Background(),
            cont.ID,
            types.ContainerRemoveOptions{
                Force:         true,
                RemoveVolumes: true,
            },
        ); err != nil {
            panic(err)
        }
    }()

    log.Println("Starting container")
    if err = cli.ContainerStart(
        context.Background(),
        cont.ID,
        types.ContainerStartOptions{},
    ); err != nil {
        panic(err)
    }

    log.Println("Waiting for container to exit")
    waitOk, waitErr := cli.ContainerWait(
        ctx,
        cont.ID,
        container.WaitConditionNotRunning,
    )
    select {
    case <-waitOk:
        log.Println("Container exited normally!")
    case err = <-waitErr:
        log.Println("Error waiting")
        panic(err)
    }
    log.Println("Should be done!")

    logOutput, err := cli.ContainerLogs(
        ctx,
        cont.ID,
        types.ContainerLogsOptions{
            ShowStdout: true,
            ShowStderr: true,
            Follow:     false,
        },
    )
    if err != nil {
        panic(err)
    }

    log.Println("Container output:")
    stdcopy.StdCopy(os.Stdout, os.Stderr, logOutput)
}

Compiling and running this yields the output:

2019/04/16 20:42:21 Creating client
2019/04/16 20:42:21              Image: ubuntu:18.04
2019/04/16 20:42:21          Host Path: /home/user/go/src/test
2019/04/16 20:42:21     Container Path: /host_files
2019/04/16 20:42:21 Creating container
2019/04/16 20:42:22 Starting container
2019/04/16 20:42:22 Waiting for container to exit
2019/04/16 20:42:22 Container exited normally!
2019/04/16 20:42:22 Should be done!
2019/04/16 20:42:22 Container output:
ls: cannot access '/host_files': No such file or directory
2019/04/16 20:42:22 Cleaning up

If you uncomment the mount-related lines, you get this output instead:

2019/04/16 20:23:32 Creating client
2019/04/16 20:23:32              Image: ubuntu:18.04
2019/04/16 20:23:32          Host Path: /home/user/go/src/test
2019/04/16 20:23:32     Container Path: /host_files
2019/04/16 20:23:32 Creating container
panic: Error response from daemon: create /home/user/go/src/test: "/home/user/go/src/test" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path

goroutine 1 [running]:
main.main()
        /home/user/go/src/test/container.go:66 +0xb0c

The error message doesn't make sense, since I am using an absolute path. Maybe I should reread the documentation for ContainerCreate.

Update 1

The docker engine API documentation contains more details about Volumes - I'm beginning to think that I'm mistaken about how docker -v /host/path:/container/path works - perhaps that is actually a bind mount and not a volume mount.

Update 2

Rubber duck debugging FTW I guess. Removing the Volumes settings, adding the Mounts back in and changing the Type to mount.TypeBind made it work:

2019/04/16 20:53:18 Creating client
2019/04/16 20:53:18              Image: ubuntu:18.04
2019/04/16 20:53:18          Host Path: /home/user/go/src/test
2019/04/16 20:53:18     Container Path: /host_files
2019/04/16 20:53:18 Creating container
2019/04/16 20:53:18 Starting container
2019/04/16 20:53:19 Waiting for container to exit
2019/04/16 20:53:19 Container exited normally!
2019/04/16 20:53:19 Should be done!
2019/04/16 20:53:19 Container output:
total XXXX
drwxr-xr-x  7 1000 1000     4096 Apr 17 03:51 .
drwxr-xr-x 34 root root     4096 Apr 17 03:53 ..
-rw-r--r--  1 1000 1000    10390 Apr 16 12:16 Gopkg.lock
-rw-r--r--  1 1000 1000     1021 Apr 16 12:16 Gopkg.toml
-rwxr-xr-x  1 1000 1000 12433827 Apr 17 03:53 container
-rw-r--r--  1 1000 1000     2421 Apr 17 03:51 container.go
2019/04/16 20:53:19 Cleaning up
  • 写回答

1条回答 默认 最新

  • doujiao1814 2019-04-17 03:56
    关注

    Removing the Volumes settings, adding the Mounts back in and changing the Type to mount.TypeBind made it work:

    2019/04/16 20:53:18 Creating client
    2019/04/16 20:53:18              Image: ubuntu:18.04
    2019/04/16 20:53:18          Host Path: /home/user/go/src/test
    2019/04/16 20:53:18     Container Path: /host_files
    2019/04/16 20:53:18 Creating container
    2019/04/16 20:53:18 Starting container
    2019/04/16 20:53:19 Waiting for container to exit
    2019/04/16 20:53:19 Container exited normally!
    2019/04/16 20:53:19 Should be done!
    2019/04/16 20:53:19 Container output:
    total XXXX
    drwxr-xr-x  7 1000 1000     4096 Apr 17 03:51 .
    drwxr-xr-x 34 root root     4096 Apr 17 03:53 ..
    -rw-r--r--  1 1000 1000    10390 Apr 16 12:16 Gopkg.lock
    -rw-r--r--  1 1000 1000     1021 Apr 16 12:16 Gopkg.toml
    -rwxr-xr-x  1 1000 1000 12433827 Apr 17 03:53 container
    -rw-r--r--  1 1000 1000     2421 Apr 17 03:51 container.go
    2019/04/16 20:53:19 Cleaning up
    

    Sigh.

    The only thing I'm not 100% sure about is if docker -v /host/path:/container/path image:tag is actually a bind mount, or not.

    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题