9

docker volume 容器卷的那些事(二)

 3 years ago
source link: https://deepzz.com/post/the-docker-volumes-permissions.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

docker volume 容器卷的那些事(二)

如果你读了docker volume 容器卷的那些事(一),我想应该不会遇到下面这些问题的,毕竟是具有指导意义的。本篇文章的内容依旧是有关 volume 的内容,主要讲诉的是如何解决非 root 用户下的文件映射问题。博主将自己常遇到的一些问题总结如下。

事情要从博主使用 prometheus 说起。当时博主使用的执行脚本类似下面这种:

$ docker run --rm \
    --name prometheus \
    -p 9090:9090 \
    -v "$(pwd)"/data:/prometheus \
    prom/prometheus:v2.0.0

应该是在其版本 2.0.0 之前,博主使用 prometheus 一切正常。突然有一天冒出这样的错误:

level=info ts=2017-12-22T12:40:09.154479277Z caller=main.go:314 msg="Starting TSDB"
level=error ts=2017-12-22T12:40:09.154587496Z caller=main.go:323 msg="Opening storage failed" err="open DB in /prometheus: open /prometheus/872424405: permission denied"

什么情况!发生了什么?没有权限?明明没有该执行脚本,不应该的啊。这才想起来咱刚刚更新过 prometheus 镜像的版本(该版本优化很大,故及时跟进)。没办法,看看它的 Dockerfile 更新了什么 #Use user nobody in Dockerfile。在 Dockerfile 中明显的看到:

USER       nobody

从以前的 root 用户切换到了 nobody 用户(为了安全考虑)。

而我们映射的目录:

drwxr-sr-x    2 root     root            40 Dec  5 02:41 data/

看到我们的 data 目录的拥有者依然是 root 用户,权限的问题必然出现了。

那么,如果你依然固执的要这样做(不使用命名容器卷)。这里提供了几种解决的办法,供参考。

在某些情况下,即使使用下面方法也不能达到效果,可能你需要尝试关闭 SELinux:setenforce 0(临时关闭)

更改目录拥有者

是的,非常容易的想到,既然这个映射出来的文件夹所有者不是 nobody,我给它改成 nobody 不就可以了吗?

首先,我们找到 nobody 用户的 id:

# 找到它的原始镜像执行命令。
$ docker run --rm quay.io/prometheus/busybox cat /etc/passwd

...
nobody:x:65534:65534:nobody:/home:/bin/false

发现,其 id 为 65534(其实这些用户uid是约定的),执行如下命令:

$ sudo chown -R 65534 data

$ ls -al data
drwxr-sr-x    3 65534   root            60 Dec 22 12:59 data/

可以看到 data 目录的所有者已经改为了 uid 为 65534 的用户。再次执行运行 prometheus 的脚本,成功。

Data Container

是的,你可以使用 Data Container 的方式进行容器卷的共享,这样也能够解决权限的问题。其基本运行方式是:

# 声明一个容器卷 /data,并在 /data 目录下新建 a.txt 文件
$ docker run --name data_container -v /data alpine touch /data/a.txt

# 挂载容器卷,查看 /data 目录下的内容
$ docker run --volumes-from container_name alpine ls /data
a.txt

当执行第二条命令时,你会看到了 a.txt 文件,说明挂载数据容器成功了。

需要说明的是,最好用同一个镜像运行数据容器,这样才能保证两者的 UID 一致,然也会出现权限问题。数据容器应该是执行一条命令就退出。

再把前面 prometheus 的例子拿来实践一下。首先,在 prometheus 的 Dockerfile 中我们看到:

# 声明容器卷
VOLUME     [ "/prometheus" ]
...
# 入口
ENTRYPOINT [ "/bin/prometheus" ]

原来 prom/prometheus 镜像就声明了一个容器卷,那么我们就不必再多次一举了。但我们需要覆盖 ENTRYPOINT 指令。

$ docker run --name data_container --entrypoint="" prom/prometheus:v2.0.0 ls

然后再次执行:

$ docker run --rm \
    --name prometheus \
    -p 9090:9090 \
    --volumes-from data_container \
    prom/prometheus:v2.0.0

有没有更好的方式去实现呢?有的,这种方式较第一种优点是自动化,不需要手动更改文件权限。具体流程是:

  1. 切换为 root 用户。
  2. 更改目录权限到当前非 root 用户。
  3. 用 gosu 以非 root 用户执行命令。

这里需要自行书写 Dockerfile 构建镜像。具体实现类似下面,新建 Dockerfile:

FROM prom/prometheus:v2.0.0
USER root

RUN mkdir -p /usr/local/bin \
  && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64" \
  && chmod +x /usr/local/bin/gosu 
 
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD [ "--config.file=/etc/prometheus/prometheus.yml", \
      "--storage.tsdb.path=/prometheus", \
      "--web.console.libraries=/usr/share/prometheus/console_libraries", \
      "--web.console.templates=/usr/share/prometheus/consoles" ]

其中 entrypoint.sh 的内容如下,它的目的就是将我们的目录的权限改成非 root 用户的权限:

#!/bin/sh

chown -R nobody /prometheus
gosu nobody prometheus "$@"

这里提到了 gosu 工具,用它来替换 sudo 从某种意义上解决了信号传递和 TTY 的问题,更多详情到其项目首页。

然后我们构建镜像,执行最初的运行脚本,成功。我们查看下映射到宿主机上的目录:

$ ls -al data
drwxr-sr-x    3 nobody   root            80 Jan 11 11:09 data

# 进入容器查看进程
$ ps
PID   USER     TIME   COMMAND
    1 root       0:00 {entrypoint.sh} /bin/sh /entrypoint.sh ...
    6 nobody     0:00 prometheus --config.file=/etc/prometheus/prometheus.yml ...

注意,standard_init_linux.go:195: exec user process caused "exec format error" 得到这个错误,可能是你没有指定运行 entrypoint.sh 的 shebang。指定如 #!/bin/sh 即可。

[1] https://denibertovic.com/posts/handling-permissions-with-docker-volumes/
[2] https://segmentfault.com/a/1190000004527476

本文链接:https://deepzz.com/post/the-docker-volumes-permissions.html参与评论 »

--EOF--

发表于 2018-01-07 19:46:00,并被添加「dockervolume」标签。

本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。更多说明 »

提醒:本文最后更新于 1077 天前,文中所描述的信息可能已发生改变,请谨慎使用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK