问题描述
使用docker运行镜像为容器时,为了以后维护目标容器中的文件简单方便,常常会使用run -v参数,将宿主机的某个目录挂在给docker容器中的某个目录
示例:
docker run -v /data:/data --name test %image_id
上述命令将运行镜像id为%image_id
的镜像为容器,容器name
为test
,并且将宿主机的/data
目录挂载给该容器的/data
目录,即实现了对容器/data目录的共享。
假设容器内/data目录的权限为:
读写权限 组名 用户名
drwxr-xr-x. root root
而宿主机/data目录权限为:
drwxr-xr-x. test test
这时容器内/data目录中有一个脚本会在容器启动时在当前目录下创建一个文件夹,此时操作系统就会给出Permission denied
提示,甚至会导致整个docker容器重启失败,这个问题的原因有些基础的同学便会一目了然。这是因为容器目录和挂载目录的组名和用户名不同,导致使用test
用户在宿主机/data
目录下没有读写权限。
参考内容
网上有很多类似的问题,解决方案大体一致,下面的链接是我解决该问题时的参考内容
多数网友的解决方案
docker挂载volume的用户权限问题,理解docker容器的uid
我的解决方案
合理的使用run命令参数
-
--privileged
,该参数可以设置是否给docker容器特权,如果该参数为true,使得docker容器内的root权限为宿主机的root权限,而非只是容器内的root权限 -
-u
,该参数可以用来显示的设置容器内应用的户用,默认是root或者可以在dockerfile中设置用户
继续上面的问题,修改run命令
docker run -v /data:/data -u root --privileged=true --name test %image_id
这时容器内/data的组名和用户名就会是root,如下
drwxr-xr-x. root root
这时容器内外的/data目录读写权限、组、用户都保持一致,就不会再出现
Permission denied
问题了
实际问题(sonatype nuxes3 docker容器启动出错,提示权限不足)
笔者某天兴致不错,放下了手机,准备把maven私服搭建一下,于是在centos服务器上执行一下命令
docker pull sonatype/nexus3
docker run -d --name nexus3 --restart=always -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -v $(pwd):/nexus-data %image_id
docker ps
然后发现STATUS不对,于是查看日志
docker logs nexus3
发现以下错误:
Unable to update instance pid: Unable to create directory /nexus-data/instances
mkdir: cannot create directory '../sonatype-work/nexus3/log': Permission denied
mkdir: cannot create directory '../sonatype-work/nexus3/tmp': Permission denied
OpenJDK 64-Bit Server VM warning: Cannot open file ../sonatype-work/nexus3/log/jvm.log due to No such file or directory
Warning: Cannot open log file: ../sonatype-work/nexus3/log/jvm.log
Warning: Forcing option -XX:LogFile=/tmp/jvm.log
java.io.FileNotFoundException: ../sonatype-work/nexus3/tmp/i4j_ZTDnGON8hezynsMX2ZCYAVDtQog=.lock (No such file or directory)
at java.io.RandomAccessFile.open0(Native Method)
at java.io.RandomAccessFile.open(RandomAccessFile.java:316)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:243)
at com.install4j.runtime.launcher.util.SingleInstance.check(SingleInstance.java:72)
at com.install4j.runtime.launcher.util.SingleInstance.checkForCurrentLauncher(SingleInstance.java:31)
at com.install4j.runtime.launcher.UnixLauncher.checkSingleInstance(UnixLauncher.java:88)
at com.install4j.runtime.launcher.UnixLauncher.main(UnixLauncher.java:67)
java.io.FileNotFoundException: /nexus-data/karaf.pid (Permission denied)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at org.apache.karaf.main.InstanceHelper.writePid(InstanceHelper.java:126)
at org.apache.karaf.main.Main.launch(Main.java:243)
at org.sonatype.nexus.karaf.NexusMain.launch(NexusMain.java:113)
at org.sonatype.nexus.karaf.NexusMain.main(NexusMain.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.exe4j.runtime.LauncherEngine.launch(LauncherEngine.java:85)
at com.install4j.runtime.launcher.UnixLauncher.main(UnixLauncher.java:69)
java.lang.RuntimeException: /nexus-data/log/karaf.log (No such file or directory)
at org.apache.karaf.main.util.BootstrapLogManager.getDefaultHandlerInternal(BootstrapLogManager.java:102)
at org.apache.karaf.main.util.BootstrapLogManager.getDefaultHandlersInternal(BootstrapLogManager.java:137)
at org.apache.karaf.main.util.BootstrapLogManager.getDefaultHandlers(BootstrapLogManager.java:70)
at org.apache.karaf.main.util.BootstrapLogManager.configureLogger(BootstrapLogManager.java:75)
at org.apache.karaf.main.Main.launch(Main.java:244)
at org.sonatype.nexus.karaf.NexusMain.launch(NexusMain.java:113)
at org.sonatype.nexus.karaf.NexusMain.main(NexusMain.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.exe4j.runtime.LauncherEngine.launch(LauncherEngine.java:85)
at com.install4j.runtime.launcher.UnixLauncher.main(UnixLauncher.java:69)
Caused by: java.io.FileNotFoundException: /nexus-data/log/karaf.log (No such file or directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at org.apache.karaf.main.util.BootstrapLogManagerSimpleFileHandler.<init>(BootstrapLogManager.java:182)
at org.apache.karaf.main.util.BootstrapLogManager.getDefaultHandlerInternal(BootstrapLogManager.java:100)
... 12 more
Error creating bundle cache.
Unable to update instance pid: Unable to create directory /nexus-data/instances
mkdir: cannot create directory '../sonatype-work/nexus3/log': Permission denied
mkdir: cannot create directory '../sonatype-work/nexus3/tmp': Permission denied
OpenJDK 64-Bit Server VM warning: Cannot open file ../sonatype-work/nexus3/log/jvm.log due to No such file or directory
Warning: Cannot open log file: ../sonatype-work/nexus3/log/jvm.log
Warning: Forcing option -XX:LogFile=/tmp/jvm.log
这时我很快猜到是-v参数惹出的麻烦,于是删除了启动失败的容器后重新从镜像运行新的容器,命令如下(基于刚才的命令删除了-v参数)
docker run -d --name nexus3 --restart=always -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -v $(pwd):/nexus-data %image_id
这时容器启动成功了,于是好奇,便进入容器内查看问题目录的权限信息,如下
drwxr-xr-x. nexus nexus
由于docker官方是不推荐以root权限启动容器的,这也是为什么nexus升级到3以后默认以用户nexus启动容器的原因,所以第一次是想把宿主机挂载过去的目录改为nexus,但是发现宿主机根本没有这个用户(注意:只是没有这个用户而已,但是这个用户的uid还是存在的),所以无法修改我的宿主机目录用户,于是利用了docker run的-u参数,指定以root用户启动,命令如下
docker run -d --name nexus3 --restart=always -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -u root --privileged=true -v $(pwd):/nexus-data %image_id
注:加
--privileged=true
是为让容器内root权限为真的root权限,上面提到过
随后容器启动成功,没有报错,再次进入docker容器查看刚才的问题目录用户信息,如下:
drwxr-xr-x. root root
至此,问题已解决!如有描述不清的地方,还请大家多多指教!