title: Golang docker library - mounting host directory volumes
body: <p>How do I perform the equivalent of:</p>
  
  <pre><code>docker run -v /host/path:/container/path image:tag
  </code></pre>
  
  <p>from Go using the official docker client package?</p>
  
  <p>I've tried different <a href="https://godoc.org/github.com/docker/docker/api/types/container#HostConfig" rel="nofollow noreferrer">Mounts</a> and <a href="https://godoc.org/github.com/docker/docker/api/types/container#Config" rel="nofollow noreferrer">Volumes</a> options within the HostOption and ConfigOption structs for the <a href="https://godoc.org/github.com/docker/docker/client#Client.ContainerCreate" rel="nofollow noreferrer">client.ContainerCreate() function</a>, but can't quite figure it out.</p>
  
  <p>In particular, the <code>Volumes</code> member (of type <code>map[string]struct{}</code>) 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.</p>
  
  <p>Code to demonstrate my problem:</p>
  
  <pre class="lang-golang prettyprint-override"><code>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(),
          &amp;container.Config{
              Image:      image,
              Entrypoint: []string{"/bin/bash", "-c", "ls -la " + containerPath},
              Volumes: map[string]struct{}{
                  hostPath: {},
              },
          },
          &amp;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 &lt;-waitOk:
          log.Println("Container exited normally!")
      case err = &lt;-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)
  }
  </code></pre>
  
  <p>Compiling and running this yields the output:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>If you uncomment the mount-related lines, you get this output instead:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>The error message doesn't make sense, since I <em>am</em> using an absolute path. Maybe I should reread the documentation for <code>ContainerCreate</code>.</p>
  
  <h2>Update 1</h2>
  
  <p><a href="https://docs.docker.com/engine/api/v1.32/#operation/ContainerCreate" rel="nofollow noreferrer">The docker engine API documentation</a> contains more details about Volumes - I'm beginning to think that I'm mistaken about how <code>docker -v /host/path:/container/path</code> works - perhaps that is actually a bind mount and not a volume mount.</p>
  
  <h2>Update 2</h2>
  
  <p><a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging" rel="nofollow noreferrer">Rubber duck debugging</a> FTW I guess. Removing the <code>Volumes</code> settings, adding the <code>Mounts</code> back in and changing the <code>Type</code> to <code>mount.TypeBind</code> made it work:</p>
  
  <pre><code>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
  </code></pre>