一、背景
需要在单独的docker环境部署一套应用程序,包括mqtt,数据库,应用等
二、问题
部署mqtt服务使用的是emqx服务。
下面是部分docker-compose.yml的内容
emqx:
container_name: minqing_emqx
image: xxx.xxx.cn/minqing/emqx/emqx
ports:
- "18083:18083"
- "1884:1883"
- "8883:8883" # 可选,安全连接
- "8083:8083"
- "8084:8084"
volumes:
- /docker-container-data/emqx5.7.1/fujian-compose/data:/opt/emqx/data
- /docker-container-data/emqx5.7.1/fujian-compose/log:/opt/emqx/log
无法创建/opt/emqx/data/configs文件夹,这个文件夹是emqx容器内的
docker run --name emqx -p 18083:18083 -p 1884:1883 -p 8883:8883 -p 8083:8084 -v /root/docker-wrl/docker-container-data/emqx571/fujian/data:/opt/emqx/data -v /root/docker-wrl/docker-container-data/emqx571/fujian/log:/opt/emqx/log xxx.xxx.cn/minqing/emqx/emqx
mkdir: cannot create directory ‘/opt/emqx/data/configs’: Permission denied
三、分析
- 通常意味着运行 Docker 容器内的用户没有足够的权限来在指定的路径下创建目录。
- 之后我尝试不要挂载运行容器,结果是可以成功运行的。所以问题可能出在挂载的操作上
关键:
- 宿主机
- 在挂载的时候
-v /root/docker-wrl/docker-container-data/emqx571/fujian/data:/opt/emqx/data
,如果宿主机上的这个目录/root/docker-wrl/docker-container-data/emqx571/fujian/data
不完整,会被自动创建。它的创建是docker。如果父目录存在,而子目录不存在,Docker 会创建子目录;如果父目录也不存在,则会报错,因为 Docker 不能创建嵌套的目录结构。 挂载目录时,通常是由 Docker 守护进程(Docker daemon)创建的
。具体来说:
Docker Daemon
:当您运行 docker run 命令并指定一个不存在的宿主机路径时,Docker Daemon 会自动尝试创建该路径。
用户权限
:创建目录的权限取决于运行 Docker Daemon 的用户。通常在 Linux 系统中,Docker Daemon 以root 用户身份
运行,因此它有权限在愿意的目录下创建新目录。- 所以,可以发现,即使容器没有运行成功,但是宿主机上的路径是被创建的了,因为是root身份创建的,所以一般它的权限是
drwxr-xr-x 2 root root 4096 Sep 2 06:21 data
和drwxr-xr-x 2 root root 4096 Sep 2 06:21 log
。
- 容器内
我在不挂载的情况下,进到容器内,看见的的log和data的权限如下:
drwxr-xr-x 2 emqx emqx 4096 Jun 26 13:39 bin
drwxr-xr-x 7 emqx emqx 4096 Sep 2 06:46 data
drwxr-xr-x 2 emqx emqx 4096 Jun 26 13:39 dynlibs
drwxr-xr-x 3 emqx emqx 4096 Jun 26 13:39 erts-14.2.5
drwxr-xr-x 5 emqx emqx 4096 Jun 26 13:39 etc
drwxr-xr-x 1 emqx emqx 4096 Jun 26 13:39 lib
drwxr-xr-x 2 emqx emqx 4096 Jun 26 13:39 log
drwxr-xr-x 2 emqx emqx 4096 Jun 26 13:39 plugins
drwxr-xr-x 3 emqx emqx 4096 Jun 26 13:39 releases
容器内部对log和data使用的是emqx用户,它对宿主机对应的两个路径是没有写权限的,只有root才有写权限。
在挂载时,容器内的指定路径下的数据写入宿主机指定路径的操作由容器内的进程执行
。
容器内的进程:当您启动容器并挂载一个宿主机目录时,容器内运行的应用程序会使用其权限将数据写入到挂载的宿主机路径。
用户权限:写入操作的权限取决于容器内进程的用户。例如:
- 如果应用程序以 root 用户身份运行,它将拥有在宿主机路径上写入的权限。
- 如果应用程序以非特权用户运行,则该用户必须在宿主机上具有相应目录的写入权限。
四、解决
那就是改变文件夹权限或者更换用户来操作。
sudo chmod -R 777 /root/docker-wrl/docker-container-data/emqx571/fujian/data
sudo chmod -R 777 /root/docker-wrl/docker-container-data/emqx571/fujian/log
注意要一块改,如果不改log的,容器也可以运行,那是因为一开始容器本来就没有往里面写内容,所以不会报错,但是之后肯定会出现异常。