Docker容器没有权限写入宿主机目录的解决方案

在应用docker容器的时候,更多的时候我们会把宿主机的目录挂载到docker容器中。

在宿主机的文件夹权限隶属于root时,我们需要将文件夹的权限用户进行 chown 设置,才能保证目录的内容的正常写入,

下面是一个例子:

使用的是docker版本的jenkins,运行后,出现如下错误:

[root@localhost CICD]# docker logs -f jenkins
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

我jenkins挂载的目录是 /opt/jenkins/xxxxx,root 用户创建,而 jenkins user的uid为1000

所以需要进行 chown 设置,如下:

sudo chown -R 1000:1000 /opt/jenkins

然后重启容器,错误就没有了。

补充:介绍两种从 Docker 容器写入卷时的文件权限处理方式

说在前面

容器常常用作原生安装工具的替代品。在主机上使用具有所需版本的容器要比使用过时的工具好的多。但是,只要容器与主机系统进行交互,文件会留下错误或损坏的权限。

幸运的是,解决该问题的方法并不需要使用脚本。

问题描述

当容器挂载一个本地目录并将文件写入其中时,其所有权由容器内的用户决定:

nicholas@host:~/source$ mkdir source
nicholas@host:~/source$ docker run -it --rm --volume $(pwd):/source --workdir /source ubuntu
root@a031d11c9515:/source# mkdir subdir
root@a031d11c9515:/source# touch subdir/newfile
root@a031d11c9515:/source# exit
exit
nicholas@host:~/source$ ls -lR
.:
total 4
drwxr-xr-x 2 root root 4096 Jul 16 19:35 subdir

./subdir:
total 0
-rw-r--r-- 1 root root 0 Jul 16 19:35 newfile
nicholas@host:~/source$ rm -rf subdir/
rm: cannot remove 'subdir/newfile': Permission denied

另外,您还可能无法删除这些目录和拥有错误所有权的文件。

解决方案1:从容器中删除

一个非常常见的解决方案是从容器内部更改文件和目录的所有权:

nicholas@host:~/source$ docker run -it --rm --volume $(pwd):/source --workdir /source ubuntu
root@d1c3bee8bb2b:/source# ls -al
total 12
drwxrwxr-x 3 1000 1004 4096 Jul 16 19:35 .
drwxr-xr-x 1 root root 4096 Jul 16 19:39 ..
drwxr-xr-x 2 root root 4096 Jul 16 19:35 subdir
root@d1c3bee8bb2b:/source# chown 1000:1000 subdir/ -R
root@d1c3bee8bb2b:/source# ls -l
total 4
drwxr-xr-x 2 1000 1000 4096 Jul 16 19:35 subdir
root@d1c3bee8bb2b:/source# exit
exit
nicholas@host:~/source$ ls -l
total 4
drwxr-xr-x 2 nicholas lpadmin 4096 Jul 16 19:35 subdir
nicholas@host:~/source$

这种方法的缺点是需要添加额外的逻辑,以及您需要知道运行该容器用户的用户 ID 和组 ID。

解决方案2:创建拥有正确所有权的文件

第二种解决方案更简洁,它将使用容器内的正确所有权创建文件和目录。Docker 提供了一个参数来设置容器内用户的用户 ID 和组 ID:

nicholas@host:~/source$ docker run -it --rm --volume $(pwd):/source --workdir /source --user $(id -u):$(id -g) ubuntu
groups: cannot find name for group ID 1004
I have no name!@bf7f355f3b65:/source$ touch newfile
I have no name!@bf7f355f3b65:/source$ exit
exit
nicholas@host:~/source$ ls -l
total 4
-rw-r--r-- 1 nicholas nicholas  0 Jul 16 19:42 newfile
drwxr-xr-x 2 nicholas lpadmin 4096 Jul 16 19:35 subdir
nicholas@host:~/source$

这种方法可以很好的帮您解决用户 ID 和组 ID 的错误。

请注意,出于安全目的,在容器内以 root 身份运行是最糟糕的做法。Dockerfile 应始终使用 USER 指令从而避免直接使用 root 权限。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • docker win ping 不通容器 避坑指南

    使用win docker-desktop,想连接容器开发,尝试了各种网络上的路子.kill my much time! 桥接是不行的, 手动添加路由也是行不通的, 所以看到这个的你不要想用常规的方法使用win宿主机连接你的linux容器,截止2020.3.29 查看原因 Networking features in Docker Desktop for Windows 也就是说 目前不支持win与linux容器使用桥接通信. 不过端口映射还是可以的,就是添加端口多的话 有点麻烦. 致我逝去的好几

  • Docker 实现容器端口绑定本地端口

    今天遇到启动镜像之后,通过HTTP请求的的方式访问不了的一个小问题,下面来记录并分享下解决办法: 常用的docker启动命令和解决办法如下所示: 一.启动docker 众所周知,启动容器的命令如下: docker run 镜像名称 二.绑定容器端口与本地端口 由于启动容器之后,本地无法直接访问容器内的端口,故而需要将本地的端口与容器的端口做一个绑定操作,从而可以通过本地端口去访问容器,设置如下: docker run -p 本地端口:容器端口 镜像名称 然后就可以通过本地的浏览器通过本地的端口访

  • 在docker容器中使用非root用户执行脚本操作

    应用容器化之后,在docker容器启动时,默认使用的是root用户执行命令,因此容器中的应用默认都是使用root用户来运行的,存在很高的安全风险,那么如何能够使用非root的业务用户来运行应用呢, 下面我将举一个简单的例子来说明. 该例子是在容器中使用自建的用户来运行一个简单的shell脚本,并将脚本输出日志持久到容器外部.接下来让我们来看从制作镜像到容器运行的全过程吧. 1.构建镜像: 我将会使用dockerfile的方式来构建镜像,基础镜像使用ubuntu 14.04(需要先拉取该镜像,do

  • Docker容器不识别宋体等字体的解决方案

    问题背景: 在使用docker部署项目的时候,由于项目中调用打印控件默认使用的是系统字体,在windows上部署没有问题,但是在docker容器中运行的时候,由于docker中没有宋体等相关字体,导致系统报错无法找到相应的字体. 解决思路: 其实就像解决linux本身没有宋体的问题一样,也可以用来解决容器问题.发现其实很多docker容器的问题最后都可以仿照linux的解决思路来处理.大体就是下载宋体ttf.ttc文件,然后将其考入容器字体目录下,重启容器即可. 解决办法: 1.查看容器支持的字

  • docker容器下配置jupyter notebook的操作

    docker容器下配置jupyter notebook,主要是为了编写python代码,更具体点是做深度学习的开发. jupyter web形式最高效的使用方式就是部署在云上,不管是cpu云服务器还是gpu的云服务器,都能快速启动使用. 而docker的出现又方便了很多在部署使用上. - 安装 docker docker分为docker CE和docker EE,一般使用docker CE(社区版本). docker可以在Linux(ubuntu.centos).MacOS.Windows或者树

  • docker用root进入容器的操作

    首先运行docker容器 运行命令是root用户 sudo docker exec -it -u root ec33c19230ca /bin/bash 补充:Docker中进入容器命令行及后台运行 Docker中我们一般会有两种执行命令的方式,一种是直接进入容器的命令行,在终端执行并查看结果,一种是在后台执行,并不会在终端查看结果. 1.进入容器命令行 su root docker run -i -t ubuntu:16.04 /bin/bash #或者执行下面这句 docker run -i

  • 解决docker run后容器出现Exited (0)情况的问题

    自己做了个centos7的openresty的Dockerfile,build之后 docker run -d -p 801:80 openresty:1.19 /usr/local/openresty/nginx/sbin/nginx 之后docker ps -a出现如下情况 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9dee2d04b3b5 openresty:1.19 "/usr/local/openrest-"

  • 解决docker 容器设置中文语言包出现的问题

    如果在Docker 中采用 docker search centos 采用 docker pull docker.io/centos 下载基础镜像 这个镜像是不支持中文的,可以采用docker attach 容器ID进入容器后采用"locale"查看 可以采用"locale -a" 查看系统语言包,会发现没有中文包 解决方案: 1.yum install kde-l10n-Chinese -y 安装语言包(针对centos 7) 2.yum reinstall gl

  • Docker容器没有权限写入宿主机目录的解决方案

    在应用docker容器的时候,更多的时候我们会把宿主机的目录挂载到docker容器中. 在宿主机的文件夹权限隶属于root时,我们需要将文件夹的权限用户进行 chown 设置,才能保证目录的内容的正常写入, 下面是一个例子: 使用的是docker版本的jenkins,运行后,出现如下错误: [root@localhost CICD]# docker logs -f jenkins touch: cannot touch '/var/jenkins_home/copy_reference_file

  • docker容器中无法获取宿主机hostname的解决方案

    在nodejs环境中测试通过,其它语言同理,只需要使用获取环境变量的方法即可. 思路: docker容器和宿主机环境是隔离的,但是可以在启动docker容器时将宿主机的主机名以环境变量的形式传入,代码在容器中获取该值即可. 操作: docker run -d -p 3000:3000 --name myTest -e HOST_Q=$(hostname) mytest:v1 # 使用-e 参数传入环境变量,值为主机名 如果使用yml文件启动: version: '3' services: mys

  • Docker容器时区调整操作

    如何检查Docker容器时区是否与宿主机一致? 1.进入宿主机, 执行以下命令: # 查看宿主机时间 [root@localhost ~]# date 2018年 06月 27日 星期三 22:42:44 CST 2.进入到容器中,执行以下命令 # 查看容器时间 root@lksjoid909090:/#date Wed Jul 27 14:43:31 UTC 2018 CST应该是指(China Shanghai Time,东八区时间) UTC应该是指(Coordinated Universa

  • docker容器与宿主机的数据交互方式总结

    前言 在生产环境中使用 Docker ,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作. 方式一.Docker cp命令 docker cp :用于容器与主机之间的数据拷贝. 语法 # 容器内文件 copy to 宿主机 docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- # 宿主机文件 copy to 容器内 docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_

  • Docker容器访问宿主机网络的方法

    最近部署一套系统,使用nginx作反向代理,其中nginx是使用docker方式运行: $ docker run -d --name nginx $PWD:/etc/nginx -p 80:80 -p 443:443 nginx:1.15 需要代理的API服务运行在宿主机的 1234 端口, nginx.conf 相关配置如下: server { ... location /api { proxy_pass http://localhost:1234 } ... } 结果访问的时候发现老是报 5

  • docker内服务访问宿主机服务的实现

    目录 1. 场景 2. 解决 3. 总结 4. 参考 1. 场景 使用windows, wsl2 进行日常开发测试工作. 但是wsl2经常会遇到网络问题.比如今天在测试一个项目,核心功能是将postgres 的数据使用开源组件synch 同步到clickhouse 这个工作. 测试所需组件 postgres kafka zookeeper redis synch容器 最开始测试时,选择的方案是, 将上述五个服务使用 docker-compose 进行编排, network_modules使用ho

  • 在docker容器中调用和执行宿主机的docker操作

    首先这个帖子,献给docker新手.当然如果你是一个老手,文中分割线后的操作方法也是一种思路. 首先说一下,如何在docker中执行宿主机的docker操作,我们管它叫docker in docker. 至于为什么要在docker中操作宿主机的docker,优点不言而喻,你既可以将你的具体需求容器化部署,又不用直接在宿主机上安装(假设我们没有办法在docker中操作宿主机的docker,那么我们只能将这样的软件程序直接安装到宿主机上,这样显然是不利于管理和维护的). 实现这种需求,其实非常简单,

  • docker容器的几种存储详解

    目录 写在前面 几种存储挂载方式 1.bind mounts 2.volumes 3.tmpfs mount 存储数据共享 写在前面 我们在上篇学习了容器网络,对容器网络驱动bridge工作原理做了较为详细的介绍,今天小作文一起看看容器中另一个关键域-存储. 容器的存储可以分为两大类: 一种是与镜像相关的即我们在<docker容器技术基础之联合文件系统OverlayFS>一文提到的容器层Copy-On-Write特性.默认情况下,在容器内创建的所有文件都存储在可写容器层上,这种直接将文件存储在

  • 详解Docker Volume 之权限管理

    Volume数据卷是Docker的一个重要概念.数据卷是可供一个或多个容器使用的特殊目录,可以为容器应用存储提供有价值的特性: 持久化数据与容器的生命周期解耦:在容器删除之后数据卷中的内容可以保持.Docker 1.9之后引进的named volume(命名文件卷)可以更加方便地管理数据卷的生命周期:数据卷可以被独立地创建和删除. 数据卷可以用于实现容器之间的数据共享 可以支持不同类型的数据存储实现 Docker缺省提供了对宿主机本地文件卷的支持,可以将宿主机的目录挂载到容器之中.由于没有容器分

  • Docker容器/bin/bash start.sh无法找到not found问题解决

    目录 项目场景: 问题描述 造成原因 解决方案 总结 项目场景: 记一次Dockerfile构建的Docker镜像,启动容器时sh: not found的问题 Dockerfile构建的Docker镜像,启动容器时找不到start.sh,执行docker run 命令时报错:/bin/sh: 1: /data/server/start.sh: not found 问题描述 Dockerfile如下(脚本正确无内容错误) FROM openjdk:8 MAINTAINER it235.com #

随机推荐