挂宿主目录的权限问题

由于容器和宿主机共用了一套内核,因此同一个uid对应的容器用户和宿主机用户(哪怕用户名不同)对于内核权限控制而言都是同一个用户。而默认情况下,如果未做特殊配置,容器里的进程默认是以root用户运行的。

这里就有两个问题:

  1. 直接以root权限运行容器不安全
  2. 以其他用户运行容器可能因为挂载宿主机目录的权限问题而蛋疼

先说第二个问题:

导致这个问题的原因,一般是因为容器内该uid的用户对宿主目录无权限导致的。 比如,容器里的mysql用户的uid是2000,而宿主当前mysql用户uid是1000,即便宿主要挂载的目录权限是mysql:mysql,容器里看到的权限也是1000:1000而权限被拒绝。

还有一种情况,宿主不存在被挂载的目录。 Docker会以root权限先创建该目录再挂载。 这就导致以普通用户运行的容器进程无权限访问该目录

这个问题最简单的处理方式就是先手动chmod 777 或者chown 2000:2000 ,再启动容器。不过这不是长久之计也违背了docker的初衷。

对于这个问题,目前大家最好的处理方式,就在entrypoint脚本里先对需要本地挂载的目录做权限配置,再启动服务。因为执行entrypoint脚本则是在启动阶段(start)所以在entrypoint.sh中可以对volume做权限配置。 当然,权限配置需要root权限,这就需要以root启动容器。

第一个问题:

以root权限运行容器,会导致容器中的进程有了适当的机会,它就可以控制宿主机上的一切!如何解决比较好呢?

有些服务可以直接以root启用,并配置其他用户运行。

比如:

  • mysqld可以mysqld --defaults-file=/etc/my.cnf --user=mysql

  • memcached可以memcached -u www

  • 甚至像ngx php-fpm 这类的服务可以直接在配置文件里指定运行worker进程的用户而master进程保持root运行

但对于像Redis这类服务呢?这类服务就需要使用Dockerfile 的USER指令去指定整个容器内部的运行用户了,当然还可以在entrypoint脚本里采用su命令切到相关的用户运行服务进程,但这种情况就会导致容器里出现一个sh父进程,如下:

[root@docker_121.201.47.196 ~]# docker exec -it redis ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 09:20 pts/0 00:00:00 /bin/sh /entrypoint /redis-se
root 6 1 0 09:20 pts/0 00:00:00 su - redis -s /bin/sh -c /redis-
redis 7 6 0 09:20 ? 00:00:02 /redis-server 0.0.0.0:6001
root 27 0 0 09:42 pts/1 00:00:00 ps -ef

这里的Redis就是直接在entrypoint脚本里采用su命令切到"redis"用户启动的。

可以发现容器里的除了redis-server,还有pid为1的sh进程。如果存粹只是为了运行Redis进程,其实也没啥问题。不过从规范的角度,容器里不应该运行不必要的多余的进程。

而且上面的栗子还存在一个问题,就是PID1进程是sh而不是redis-server,这样docker stop 该容器时,里面的redis-sever进程将无法接收到关闭的信号而导致超时十秒被docker强杀,这在需要数据落地的场景下是不被允许的。比如mysql的docker容器一般只跑mysqld进程而不需要mysqld_safe。

详参:https://www.oschina.net/translate/docker-and-the-pid-1-zombie-reaping-problem?spm=5176.100239.blogcont5545.17.qOGovX

gosu

那对于上面redis引出的这个问题,该如何解决最好呢?

这里推荐在entrypoint脚本里使用gosu来替换su,来切换用户运行程序

具体gosu的解析,可以参考:https://segmentfault.com/a/1190000004527476

Redis的栗子

对于上面扯的几个问题,这里用redis作为栗子重写Dockerfile https://www.cnblogs.com/wshenjin/p/9328763.html

Dockerfile:

FROM centos

COPY ["src","/src"]

RUN groupadd -g 1002 redis \
&& useradd -u 1002 -g redis -s /sbin/nologin redis ;\
yum -y install tcl-8.5* make gcc gcc-c++ \
&& yum clean all ;\
cd /src/ \
&& cp redis_entrypoint.sh / \
&& cp gosu /usr/local/bin/ \
&& cp redis.conf /etc/ \
&& tar xf redis-3.2.7.tar.gz \
&& cd redis-3.2.7/ \
&& make MALLOC=libc \
&& cp src/{redis-benchmark,redis-check-aof,redis-cli,redis-sentinel,redis-server} /usr/local/bin/ ;\
cd / ;\
mkdir -p /data/redis \
&& chown redis:redis -R /data/redis ;\
echo "/usr/local/bin/redis-cli -h 127.0.0.1 -p 6001 -a $(awk '/^requirepass/{print $NF}' /etc/redis.conf) save" >> /root/redis_stop ;\
echo "sleep 5s" >> /root/redis_stop ;\
echo "/usr/local/bin/redis-cli -h 127.0.0.1 -p 6001 -a $(awk '/^requirepass/{print $NF}' /etc/redis.conf) shutdown" >> /root/redis_stop ;\
echo "/usr/local/bin/redis-cli -h 127.0.0.1 -p 6001 -a $(awk '/^requirepass/{print $NF}' /etc/redis.conf) info" >> /root/redis_info ;\
echo "/usr/local/bin/redis-cli -h 127.0.0.1 -p 6001 -a $(awk '/^requirepass/{print $NF}' /etc/redis.conf) bgsave" >> /root/redis_bgsave ;\
chmod 700 /root/redis_* ;\
yum remove -y iputils* \
bind* \
vim* \
make \
cmake \
cpp \
acl \
rootfiles \
lzo \
readline-devel \
python-chardet \
hostnamed \
bus-python \
gobject-introspection \
libxml2-python \
python-gobject-base \
basesystem \
libgomp \
libstdc++-devel \
glibc-headers \
mpfr \
passwd \
yum-plugin-ovl \
dbus-glib \
python-kitchen \
ncurses-devel \
kernel-headers \
gpg-pubkey \
yum-util ;\
userdel mail ;\
userdel ftp ;\
userdel games ;\
cp /usr/share/zoneinfo/Asia/Shanghai /etc/ ;\
ln -svf /etc/Shanghai /etc/localtime ;\
rm -rf /src /root/.bash* /root/.cshrc /root/.tcshrc /var/cache /usr/share/zoneinfo EXPOSE 6001 HEALTHCHECK --interval=60s --timeout=5s CMD /usr/local/bin/redis-cli -h 127.0.0.1 -p 6001 -a $(awk '/^requirepass/{print $NF}' /etc/redis.conf) ping | grep -i PONG || exit 1 ENTRYPOINT ["/redis_entrypoint.sh"]

redis_entrypoint.sh:

#/bin/sh

chown redis:redis -R /data/redis/ #redis数据目录,log pid rdb。
exec gosu redis /bin/sh -c "/usr/local/bin/redis-server /etc/redis.conf"

Redis用到的唯一目录是/data/redis/,entrypoint脚本会进行权限处理。当挂载宿主目录时,不论宿主目录如何,entrypoint脚本都会处理好。

这样得到的容器内部进程就如下:

[root@docker_121.201.47.196 ~]# docker exec -it redis ps -ef
UID PID PPID C STIME TTY TIME CMD
redis 1 0 0 Mar08 pts/0 00:12:15 /usr/local/bin/redis-server 0.0.0.0:6001
root 18206 0 0 17:42 pts/1 00:00:00 ps -ef

Docker volume权限导致的几个问题的更多相关文章

  1. 解决 Windows Docker 安装 Gitlab Volume 权限问题

    本文首发于我的个人博客,解决 Windows Docker 安装 Gitlab Volume 权限问题 ,欢迎访问! 记录一下 Windows10 下 Docker 安装 Gitlab 的步骤. Ca ...

  2. Docker volume speed up npm install

    上一节决定在Jenkins中采用Docker作为构建环境,于是就可以为所欲为的使用各种node版本编译我们的项目.解决了版本切换问题.然而,Docker设计的目的就是纯净的执行环境,因此每次运行doc ...

  3. docker volume创建、备份、nfs存储

    docker存储volume #环境 centos7.4 , Docker version 17.12.0-ce docker volume创建.备份.nfs存储 #docker volume 数据存 ...

  4. 理解OpenShift(5):从 Docker Volume 到 OpenShift Persistent Volume

    理解OpenShift(1):网络之 Router 和 Route 理解OpenShift(2):网络之 DNS(域名服务) 理解OpenShift(3):网络之 SDN 理解OpenShift(4) ...

  5. Docker学习笔记之docker volume 容器卷的那些事(二)

    预览目录 更改目录拥有者 Data Container 切换用户 参考文章 0x00 概述 如果你读了docker volume 容器卷的那些事(一),我想应该不会遇到下面这些问题的,毕竟是具有指导意 ...

  6. Docker学习笔记之docker volume 容器卷的那些事(一)

    预览目录 volume 方式 相关用例 使用方式 使用 volume driver bind mount 方式 相关用例 使用方式 配置selinux标签 配置macOS的安装一致性 tmpfs 方式 ...

  7. Docker - 命令 - docker volume

    概述 docker volume 命令 背景 docker 容器的存储, 通常需要独立于镜像 docker volume 就是负责这块的命令 1. 写在 docker volume 之前 概述 doc ...

  8. windows 文件权限导致的 git 问题

    windows 文件权限导致的 git 问题 在 windows 上使用 git 时,会遇到明明什么都没有改动,但是 git status 显示一堆文件被修改.这时,通过 git diff 可看到什么 ...

  9. 关于修改了db2 instance下面文件夹权限导致的不可连接

    前一段时间,我修改了db2inst1目录下的所有文件的权限,目的是方便其他用户访问和查看里面的文件信息.可是修改了之后,我用IBM data studio就始终连接不上数据库了. 查看了错误代码,看提 ...

随机推荐

  1. c#中string的一些基本用法

    .string的Split方法的使用 这个例子就是通过制定的符号来将词组分开,Splite(分割的字符,分割的份数) using System; using System.Collections; p ...

  2. 网络编程之socketserver以及socket更多方法

    关于socketserver 关于socket的更多方法 服务端套接字函数: s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始tcp监听 s.accept () 被动接受tc ...

  3. Java作业四(2017-10-8)

    import java.util.Scanner; public class Helloworld { public static void main(String[] args) { System. ...

  4. PL-SVO公式推导及代码解析:地图点重投影和特征对齐

    对当前帧进行地图点重投影和特征对齐 // map reprojection & feature alignment SVO_START_TIMER("reproject") ...

  5. [dev] 中文版内核代码编码规范

    我是我最喜欢的编码规范.并始终坚持. https://www.kernel.org/doc/html/v4.15/translations/zh_CN/coding-style.html

  6. APICloud · 跨越2018,技术改变世界

    在APICloud发展轨迹中, 2018注定是疾速的一年, 更多的风口趋势和现象级应用背后, 是技术在推动着世界的加速转动. APICloud所提供的技术服务,在混合之力的驱动下不断完善升级,“让你的 ...

  7. IDEA导入Git项目后右键项目找不到Git选项的解决方法

    进入Setting -> version Control -> 在下图的第二步中是否有灰色的Module,选中它->点击第三步的+即可 转自:https://blog.csdn.ne ...

  8. vue-cli 创建项目失败

    vue-cli 创建一个vue项目报错 npm code 404. 尝试解决方法都有,我是第3种方法生效 更新npm 重新安装nodejs vue-cli@3.0.1 在创建项目的时候,不能开启其他v ...

  9. 时区切换导致quartz定时任务没有触发问题

    时区切换对Quartz的cron表达式有影响,切换的1小时内停止触发定时任务,导致sla没有定时清空内存计数,误发限流. 美国夏令时PST切换到冬令时PDT,会有时间跳变.不带时区跳变的,会出现时间重 ...

  10. 获奖感想与Java阶段性学习总结

    获奖感想 其实我早就知道有小黄衫这个东西,而且它就在我的目标清单里,不过没想到娄老师发的这么早.我想小黄衫代表着的是老师对我这一阶段来学习成果和努力的肯定,虽然Java学习中付出很多时间精力,现在也值 ...