无法在Go中为Docker容器编写有效的挂载路径。

huangapple go评论72阅读模式
英文:

cannot write valid mount path for docker container in go

问题

我正在尝试启动一个测试容器来测试我的数据库,我正在使用测试容器。以下是我设置容器的一段代码:

func createContainer(ctx context.Context) (testcontainers.Container, *pgxpool.Pool, string, error) {
    var env = map[string]string{
        "POSTGRES_PASSWORD": DbPass,
        "POSTGRES_USER":     DbUser,
        "POSTGRES_DB":       DbName,
    }
    var port = "5432/tcp"

    // /Users/<path>:/<container path> 
    path := `/c/Users/pizhlo21/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration:/usr/app`

    req := testcontainers.GenericContainerRequest{
        ContainerRequest: testcontainers.ContainerRequest{
            Image:        "postgres:latest",
            ExposedPorts: []string{port},
            Env:          env,
            WaitingFor:   wait.ForLog("database system is ready to accept connections"),
            VolumeMounts: map[string]string{"/docker-entrypoint-initdb.d": path},
            SkipReaper: true,
        },
        Started: true,
    }
    container, err := testcontainers.GenericContainer(ctx, req)
    if err != nil {
        return container, nil, "", fmt.Errorf("unable to start container: %v", err)
    }
    ...
}

但是我从Docker那里得到了一个错误:failed to setup testunable to start container: failed to create container: Error response from daemon: create /docker-entrypoint-initdb.d: "/docker-entrypoint-initdb.d" 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
有时这个错误看起来像这样:failed to setup testfailed to start container: failed to create container: Error response from daemon: invalid mount config for type "volume": invalid mount path: '\"c/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration/000001_init_schema.up\"' mount path must be absolute

我尝试了很多不同的路径变化,例如:
//c/Users/...
c/Users/...
/%cd%/Desktop/...
$HOME/Desktop/Folder/...
但是没有什么帮助。

如何正确做到这一点?

英文:

I'm trying to start a test container to test my database. I'm using test containers.
Here is a piece of code how I setup a container:

func createContainer(ctx context.Context) (testcontainers.Container, *pgxpool.Pool, string, error) {
var env = map[string]string{
		&quot;POSTGRES_PASSWORD&quot;: DbPass,
		&quot;POSTGRES_USER&quot;:     DbUser,
		&quot;POSTGRES_DB&quot;:       DbName,
	}
	var port = &quot;5432/tcp&quot;

	// /Users/&lt;path&gt;:/&lt;container path&gt; 
	path := `/c/Users/pizhlo21/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration:/usr/app`

	req := testcontainers.GenericContainerRequest{
		ContainerRequest: testcontainers.ContainerRequest{
			Image:        &quot;postgres:latest&quot;,
			ExposedPorts: []string{port},
			Env:          env,
			WaitingFor:   wait.ForLog(&quot;database system is ready to accept connections&quot;),
			VolumeMounts: map[string]string{&quot;/docker-entrypoint-initdb.d&quot;: path},
			SkipReaper: true,
		},
		Started: true,
	}
	container, err := testcontainers.GenericContainer(ctx, req)
	if err != nil {
		return container, nil, &quot;&quot;, fmt.Errorf(&quot;unable to start container: %v&quot;, err)
	}
...

but I got an error from Docker: failed to setup testunable to start container: failed to create container: Error response from daemon: create /docker-entrypoint-initdb.d: &quot;/docker-entrypoint-initdb.d&quot; includes invalid characters for a local volume name, only &quot;[a-zA-Z0-9][a-zA-Z0-9_.-]&quot; are allowed. If you intended to pass a host directory, use absolute path.
<br><Br>Sometimes this error looks like: failed to setup testfailed to start container: failed to create container: Error response from daemon: invalid mount config for type &quot;volume&quot;: invalid mount path:
&#39;&quot;c/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration/000001_init_schema.up&quot;&#39; mount path must be absolute

I've tried many variations of my path such as:<br>
//c/Users/...
c/Users/...
/%cd%/Desktop/...
$HOME/Desktop/Folder/...<br>
but nothing helped me.

How to do it correct?

答案1

得分: 1

TL;DR

VolumeMounts: map[string]string{&quot;/docker-entrypoint-initdb.d&quot;: path},

替换为

BindMounts: map[string]string{&quot;/docker-entrypoint-initdb.d&quot;: path},

问题1

> "/docker-entrypoint-initdb.d" 包含无效字符,本地卷名称只允许使用 "[a-zA-Z0-9][a-zA-Z0-9_.-]"。

重要的是要知道有三种类型的挂载

  • 卷(Volumes) 存储在由Docker管理的主机文件系统的一部分上(在Linux上为/var/lib/docker/volumes/)。非Docker进程不应修改文件系统的这部分。卷是在Docker中持久保存数据的最佳方式。
  • 绑定挂载(Bind mounts) 可以存储在主机系统的_任何位置_。它们甚至可以是重要的系统文件或目录。Docker主机或Docker容器上的非Docker进程可以随时修改它们。
  • tmpfs挂载 仅存储在主机系统的内存中,永远不会写入主机系统的文件系统。

VolumeMounts 用于指定卷挂载。从 github.com/testcontainers/testcontainers-go@v0.12.0 开始,VolumeMounts 中的条目值存储卷名称,只允许使用 [a-zA-Z0-9][a-zA-Z0-9_.-],这就是为什么你看到错误消息。顺便说一下,要看到上面的错误消息,你的代码必须类似于这样(注意 /docker-entrypoint-initdb.d 是值而不是键):

VolumeMounts: map[string]string{path: &quot;/docker-entrypoint-initdb.d&quot;},

问题2

> 类型为"volume"的挂载配置无效:挂载路径无效:"c/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration/000001_init_schema.up" 挂载路径必须是绝对路径

要看到此错误消息,你的代码必须类似于这样:

VolumeMounts: map[string]string{`&quot;/c/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration/000001_init_schema.up&quot;`: &quot;/docker-entrypoint-initdb.d&quot;},

github.com/testcontainers/testcontainers-go@v0.12.0 开始,VolumeMounts 中的条目键存储挂载路径。由于挂载路径包含双引号(&quot;),它是无效的。Docker守护程序首先验证挂载路径。这就是为什么你看到错误消息的原因。


考虑升级 github.com/testcontainers/testcontainers-go

在版本 v0.13.0 中,ContainerRequest.BindMountsContainerRequest.VolumeMountsContainerRequest.Mounts 替换。这是因为“基于映射的数据结构在某种程度上令人困惑。通过引入所有组件的专用类型来避免混淆,以便获得IDE和编译器的帮助”(参见 PR#386)。

升级到 github.com/testcontainers/testcontainers-go@v0.21.0 后,可以使用以下方式指定绑定挂载:

Mounts: testcontainers.Mounts(
	testcontainers.BindMount(path, &quot;/docker-entrypoint-initdb.d&quot;),
),
英文:

TL;DR

Replace

VolumeMounts: map[string]string{&quot;/docker-entrypoint-initdb.d&quot;: path},

with

BindMounts: map[string]string{&quot;/docker-entrypoint-initdb.d&quot;: path},

Issue 1

> "/docker-entrypoint-initdb.d" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed.

It's important to know that there are three types of mounts:

  • Volumes are stored in a part of the host filesystem which is managed by Docker (/var/lib/docker/volumes/ on Linux). Non-Docker processes should not modify this part of the filesystem. Volumes are the best way to persist data in Docker.
  • Bind mounts may be stored anywhere on the host system. They may even be important system files or directories. Non-Docker processes on the Docker host or a Docker container can modify them at any time.
  • tmpfs mounts are stored in the host system’s memory only, and are never written to the host system’s filesystem.

VolumeMounts is for specifying the volume mounts. As of github.com/testcontainers/testcontainers-go@v0.12.0, the value of an entry in VolumeMounts stores the volume name, which only allows [a-zA-Z0-9][a-zA-Z0-9_.-], that's why you see the error message. BTW, to see the error message above, your code must be something like this (note that /docker-entrypoint-initdb.d is the value instead of the key):

VolumeMounts: map[string]string{path: &quot;/docker-entrypoint-initdb.d&quot;},

Issue 2

> invalid mount config for type "volume": invalid mount path: '"c/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration/000001_init_schema.up"' mount path must be absolute

To see this error message, your code must be something like this:

VolumeMounts: map[string]string{`&quot;/c/Desktop/Folder/golang/TgBotReminder/internal/db/postgresql/migration/000001_init_schema.up&quot;`: &quot;/docker-entrypoint-initdb.d&quot;},

As of github.com/testcontainers/testcontainers-go@v0.12.0, the key of an entry in VolumeMounts stores the mount path. Since the mount path contains the double quotes (&quot;), it's invalid. The docker daemon verifies the mount path first. That's why you see the error message.


Consider upgrading github.com/testcontainers/testcontainers-go

In release v0.13.0, ContainerRequest.BindMounts and ContainerRequest.VolumeMounts are replaced with ContainerRequest.Mounts. That's because "the map based data structure is somehow confusing. This change avoids confusion by introducing dedicated types for all components to get help by IDEs and the compiler". (see PR#386).

After upgrading to github.com/testcontainers/testcontainers-go@v0.21.0, the bind mounts can be specified with:

Mounts: testcontainers.Mounts(
	testcontainers.BindMount(path, &quot;/docker-entrypoint-initdb.d&quot;),
),

huangapple
  • 本文由 发表于 2023年7月8日 02:03:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76639256.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定