如何挂载容器可写主机目录?

Posted

技术标签:

【中文标题】如何挂载容器可写主机目录?【英文标题】:How to mount container-writable host directory? 【发布时间】:2016-06-23 04:31:24 【问题描述】:

我正在尝试使用 Docker 运行 ELK 堆栈。我发现docker-elk 已经使用docker-compose 为我设置了配置。

我想将 elasticsearch 数据存储在主机而不是容器上。根据 docker-elk 的 README,我在 elasticsearchdocker-compose.yml 部分添加了 volumes 行:

elasticsearch:
  image: elasticsearch:latest
  command: elasticsearch -Des.network.host=0.0.0.0
  ports:
    - "9200"
    - "9300"
  volumes:
    - ../../env/elasticsearch:/usr/share/elasticsearch/data

但是,当我运行 docker-compose up 时,我得到:

$ docker-compose up
Starting dev_elasticsearch_1
Starting dev_logstash_1
Starting dev_kibana_1
Attaching to dev_elasticsearch_1, dev_logstash_1, dev_kibana_1
kibana_1        | Stalling for Elasticsearch
elasticsearch_1 | [2016-03-09 00:23:35,193][WARN ][bootstrap                ] unable to install syscall filter: seccomp unavailable: your kernel is buggy and you should upgrade
elasticsearch_1 | Exception in thread "main" java.lang.IllegalStateException: Unable to access 'path.data' (/usr/share/elasticsearch/data/elasticsearch)
elasticsearch_1 | Likely root cause: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/elasticsearch
elasticsearch_1 |   at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
elasticsearch_1 |   at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
elasticsearch_1 |   at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
... etc ...

查看../../env,确实创建了elasticsearch目录,但它是空的。如果我创建../../env/elasticsearch/elasticsearch,那么我会收到/usr/share/elasticsearch/data/elasticsearch/nodes 的访问错误。如果我创建/nodes,那么我会收到/nodes/0 的错误,等等...

简而言之,容器似乎没有目录的写权限。

如何让它拥有写权限?我试过chmod a+wx ../../env/elasticsearch,然后它设法创建下一个目录,但是那个目录有drwxr-xr-x的权限,它又卡住了。

我不喜欢必须以 root 身份运行它的想法。

【问题讨论】:

docker-compose run --rm elasticsearch stat -c "%U %G" /usr/share/elasticsearch/data 的输出是什么? @kojiro:我得到UNKNOWN staff 【参考方案1】:

Docker 不会在其基础镜像中担心这些事情,因为它希望您使用卷或卷容器。安装到主机获得二等支持。但只要拥有该目录的 UID 不为零(而且它似乎不是基于我们的评论交换),您应该能够以已经拥有该目录的用户身份运行 elasticsearch。您可以尝试从容器中删除并重新添加 elasticsearch 用户,并指定其 UID。

您需要在入口点执行此操作,因此最好的办法是构建自定义容器。使用以下内容创建一个名为 my-entrypoint 的文件:

#!/bin/bash

# Allow running arbitrary one-off commands
[[ $1 && $1 != elasticsearch ]] && exec "$@"
# Otherwise, fix perms and then delegate the rest to vanilla
target_uid=$(stat -c %u /usr/share/elasticsearch/data)
userdel elasticsearch
useradd -u "$target_uid" elasticsearch
. /docker-entrypoint "$@"

确保它是可执行的。然后创建一个包含以下内容的 Dockerfile:

FROM elasticsearch
COPY my-entrypoint /
ENTRYPOINT ["/my-entrypoint"]

最后更新你的 docker-compose.yml 文件:

elasticsearch:
  build: .
  command: elasticsearch -Des.network.host=0.0.0.0
  ports:
    - "9200"
    - "9300"
  volumes:
    - ../../env/elasticsearch:/usr/share/elasticsearch/data

现在,当您运行 docker-compose up 时,它应该使用您的更改构建一个弹性搜索容器。

(我不得不这样做一次with apache for Magento。)

【讨论】:

啊有趣!我尝试了你在这里写的东西,但它最终没有工作......首先我认为它是/docker-entrypoint.sh,而不是/docker-entrypoint,但后来它仍然没有工作。不过,根据您的前两句话,我决定让我的生活更轻松,只使用命名卷。

以上是关于如何挂载容器可写主机目录?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Docker 将容器目录挂载到主机上

使用 Docker 将容器目录挂载到主机上

使用 Docker 将容器目录挂载到主机上

docker-tmpfs挂载

docker容器挂载宿主机目录后,启动状态一直是restarting

Docker容器数据卷挂载使用