Linux系统的权限管理是由uid和gid负责,Linux系统会检查创建进程的uid和gid,以确定它是否有足够的权限修改文件,而非是通过用户名和用户组来确认。
同样,在docker容器中主机上运行的所有容器共享同一个内核也可以理解为共享权限管理方式。
在volume挂载目录时默认属于root用户,如果没有chown给其他用户的话,在Volume卷中创建的文件和文件夹将拥有与在容器中的卷相同的uid:gid(数字)。
namespace隔离技术:docker容器内部依然是以"root"的权限管理,但实际只有普通用户的权限,从而达到权限隔离的效果。
1. redis镜像,使用hd用户启动容器,参数带上-user,data和log文件夹是root
不管是以root用户还是以普通用户(有启动docker容器的权限)启动docker容器,容器进程和容器内的用户权限都是root
新建hd用户,以hd用户权限启动容器,并在宿主机中有root权限"/docker/hd"的目录 进行权限测试
[hd@centos3 ~]$ sudo docker run -v /docker/hd:/docker/hd -it --name centos-hd centos:7.7.1908 bash
[root@7ec6c43eee2c /]# cd /docker/hd
[root@7ec6c43eee2c hd]# echo "a" >a.txt
[root@7ec6c43eee2c hd]# cat a.txt
a
[root@7ec6c43eee2c hd]#
我们启动容器后,我们看到hd用户变为root用户了
查看
新增–user参数,使容器启动用户变成指定的hd用户,并在宿主机中有root权限"/docker/hd"的目录 进行权限测试,发现并不能操作拥有root权限的文件了
# hd 用户测试,当前hd用户的uid是1000
[hd@centos3 ~]$ id
uid=1000(hd) gid=1000(hd) groups=1000(hd) context=unconfined_u:unconfined_r:unconfined_t:s0
# 以hd用户启动容器
[hd@centos3 ~]$ sudo docker run -v /docker/hd:/docker/hd --user 1000 -it --name centos-hd centos:7.7.1908 bash
# 当前hd用户的uid是1000,gid和groups都是root
bash-4.2$ id
uid=1000 gid=0(root) groups=0(root)
# 写入内容,发现没有权限(Permission denied)
bash-4.2$ cd /docker/hd
bash-4.2$ echo "a" >a.txt
bash: a.txt: Permission denied
我们发现容器中的uid号和实际主机中的uid号一样,也验证了docker容器使用宿主机的内核。可以一定程度进行权限管理。
grubby --args="namespace.unpriv_enable=1 user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"
echo "user.max_user_namespaces=15076" >> /etc/sysctl.conf
vim /etc/docker/daemon.json
新增内容
"userns-remap": "default",
default默认就是docker自动创建的用户dockremap,然后重启docker。
修改此项配置需要慎重,如果是已经部署了一套docker环境,启用此选项后,会切换到隔离环境,以前的docker容器将无法使用!
vim /etc/subgid
dockremap:22222:65536
vim /etc/subuid
dockremap:22222:65536
cat /etc/subgid
cat /etc/subuid
③Centos需要手动输入id值映射范围
systemctl restart docker
重启docker后再次测试效果,发现文件权限已经变成nobody,但docker容器内部依然是以"root"的权限管理,但实际只有普通用户的权限,从而达到权限隔离的效果。
我们这里使用elasticsearch作为案例
FROM centos:7.7.1908
# 创建者
MAINTAINER HuiDian
COPY elasticsearch-7.4.2-linux-x86_64.tar.gz /home
COPY elasticsearch-analysis-ansj-7.4.2.0-release.zip /home
COPY elasticsearch.yml /home
COPY jvm.options /home
ENV JAVA_HOME /docker/elasticsearch-7.4.2/jdk
RUN mkdir -p /docker/ &&\
yum install -y unzip zip lrzsz vim &&\
# 解压
mv /home/elasticsearch-7.4.2-linux-x86_64.tar.gz /docker/ &&\
cd /docker &&\
tar -zxvf elasticsearch-7.4.2-linux-x86_64.tar.gz &&\
# ansj 分词器 解压到指定目录
unzip /home/elasticsearch-analysis-ansj-7.4.2.0-release.zip -d /docker/elasticsearch-7.4.2/plugins/ansj &&\
# 添加配置文件
mv /home/elasticsearch.yml /docker/elasticsearch-7.4.2/config/ &&\
mv /home/jvm.options /docker/elasticsearch-7.4.2/config/ &&\
# 创建es用户
useradd es && chown -R es:es /docker/elasticsearch-7.4.2 &&\
# 删掉安装包
rm -rf /docker/elasticsearch-7.4.2-linux-x86_64.tar.gz &&\
rm -rf /home/elasticsearch-analysis-ansj-7.4.2.0-release.zip
# cmd,run命令使用es用户启动
USER es
EXPOSE 9200
EXPOSE 9300
CMD "/docker/elasticsearch-7.4.2/bin/elasticsearch"
docker run -d \
--name elasticsearch \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch_huidian:7.4.2
docker rm -f elasticsearch
docker run -id --name=elasticsearch elasticsearch_huidian:7.4.2
docker exec -it elasticsearch bash -c "whoami && id"
docker exec -it elasticsearch bash -c "ls -la /docker/elasticsearch-7.4.2/data"
docker rm -f elasticsearch
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -v /home/hd/docker/elasticsearch/data:/docker/elasticsearch-7.4.2/data elasticsearch_huidian:7.4.2
docker ps -a
docker rm -f elasticsearch
docker run -it --name=elasticsearch -v /home/hd/docker/elasticsearch/data:/docker/elasticsearch-7.4.2/data elasticsearch_huidian:7.4.2 bash -c "whoami && id"
docker rm -f elasticsearch
docker run -it --name=elasticsearch -v /home/hd/docker/elasticsearch/data:/docker/elasticsearch-7.4.2/data elasticsearch_huidian:7.4.2 bash -c "ls -la /docker/elasticsearch-7.4.2/data"
当容器启动的时候,如果容器要对数据卷的主机目录进行修改或者添加,那么会将权限提升为root。也就是说/docker/elasticsearch-7.4.2/data目录和nodes目录会将es的权限提升为root,也就是当前我们看到的。
当"es"用户的进程访问"/docker/elasticsearch-7.4.2/data"目录时,没有root权限,会出现 Permission denied的问题。
当前路径下"data"目录的拥有者是"root",这是因为这个目录是Docker进程缺省创建出来的。
把当前目录的拥有者赋值给uid 1000,再启动"elasticsearch"容器就一切正常了
chown -R 1000:1000 /home/hd/docker/elasticsearch/data
docker rm -f elasticsearch
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -v /home/hd/docker/elasticsearch/data:/docker/elasticsearch-7.4.2/data elasticsearch_huidian:7.4.2
docker ps -a
当我们再进入容器内部查看"/home/hd/docker/elasticsearch/data"目录的权限,其拥有者已经变成 “es”
在宿主机上我们看到的"data"目录的拥有者是"hd",这是因为"hd"用户的uid是1000。
而容器中es用户的uid也是1000,说明hd和es本质是同一个用户
docker exec -it elasticsearch bash -c "ls -la /docker/elasticsearch-7.4.2/data"
在4.3.1中,我们在宿主机上执行chown命令时采用了uid而不是具体的用户名,这样就可以保证设置正确的拥有者。
问题虽然解决了,但思考并没有结束。因为当使用本地数据卷时,elasticsearch容器会依赖宿主机目录权限的正确性,这会给自动化部署带来额外的工作。
有没有方法让elasticsearch容器为数据卷自动地设置正确的权限呢?这个问题对很多以non-root方式运行的应用也都有借鉴意义.
利用Data Container的方法在容器间共享数据卷。这样就规避了解决宿主机上数据卷的权限问题。由于在1.9版本之后,Docker提供了named volume来取代纯数据容器。
让容器中以root用户启动,在容器启动脚本中利用"chown"命令来修正数据卷文件权限,之后切换到non-root用户来执行程序
进入容器,查看当前容器的用户id是宿主机是否一致,不一致就通过下面命令修改为一致,再将容器打包为镜像,这样就保证了容器和宿主机用户是同一个用户id,也就没有权限问题了。
usermod -u 1002 hd
groupmod -g 1002 hd
# 让容器中以root用户启动
USER root
# 在容器启动脚本中利用"chown"命令来修正数据卷文件权限
chown -R 1000:1000 /docker/elasticsearch-7.4.2/data
# 切换到es用户来执行程序
CMD "su es /docker/elasticsearch-7.4.2/bin/elasticsearch"