docker - Golang docker library - 挂载主机目录卷

标签 docker go

我如何执行相当于:

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

从 Go 使用官方 docker 客户端包?

我试过不同的 MountsVolumes client.ContainerCreate() function 的 HostOption 和 ConfigOption 结构中的选项, 但不太明白。

特别是 Volumes 成员(map[string]struct{} 类型)特别难搞清楚如何使用,我找不到关于结构中应该存在哪些值的任何文档。

演示我的问题的代码:

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\n", image)
    log.Printf("         Host Path: %s\n", hostPath)
    log.Printf("    Container Path: %s\n", 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)
}

编译并运行它会产生输出:

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

如果取消注释与挂载相关的行,则会得到以下输出:

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

错误消息没有意义,因为我使用的是绝对路径。也许我应该重新阅读 ContainerCreate 的文档。

更新1

The docker engine API documentation包含有关卷的更多详细信息 - 我开始认为我对 docker -v/host/path:/container/path 的工作方式有误 - 也许这实际上是绑定(bind)安装而不是卷挂载。

更新2

Rubber duck debugging我想是的。删除 Volumes 设置,重新添加 Mounts 并将 Type 更改为 mount.TypeBind 使其工作:

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

最佳答案

删除 Volumes 设置,重新添加 Mounts 并将 Type 更改为 mount.TypeBind它有效:

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

感叹。

我唯一不能 100% 确定的是 docker -v/host/path:/container/path image:tag 实际上是 绑定(bind)挂载, 或者不是。

关于docker - Golang docker library - 挂载主机目录卷,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55718603/

相关文章:

oracle - Go lang 连接到 Oracle 9i(使用 go-oci8)

testing - Golang 有 libfaketime 替代品吗?

go - 尽管在启动应用程序时是私有(private)的,但如何从主包调用 main() 函数?

linux - 保持进程在容器上运行的正确方法

docker - docker 中的 systemctl 错误 'Failed to connect to bus: No such file or directory'

docker - 你如何在 Windows 上安装 docker 套接字?

dictionary - 将数组类型的映射键转换为2D slice

c# - 如何通过 docker 使用启动配置文件运行 .net 核心应用程序

sql-server - 无法从 Docker 容器连接到 SQL Server

go - 访问接口(interface)内的结构值