Docker 相同GID对应不同用户组导致的无权限问题

关于架构

  • PHP7.2
  • OpenResty
  • Redis
  • MySQL

更新于:2018-7-11

跟同事验证之后,似乎并不是我描述的那样。两个容器内,虽然分组的名称不同,但是只要GID相同,就有权限。至于为什么会造成nginx启动后没有权限读取socket文件,是因为在nginx.conf文件中没有指定运行用户的原因。

比如我的nginx是基于alpine构建的。php所运行的容器的www-data的GID是33,对应到alpine中的GID:33是xfs,需要在nginx.conf中添加进 user xfs就ok了。如果并不想这么干,那就需要执行下面的命令deluser xfs && \
addgroup -g 33 -S www-data && adduser -u 33 -D -S -G www-data www-data
删掉xfs这个用户,然后重新新建一个GID为33,用户组为www-data,用户名为www-data的用户

分割线


下面是错误的解答

上面的架构在Linux中有个非常常见的名字是LNMP。基本上是在相同的系统中进行的配置。因此,常规的业务中几乎不会有人会在LNMP这架构上遇到标题中的问题。

但是在Docker中,可以有PHP环境是Debian,OpenResty环境是alpine这样的搭配。

验证无权限问题

拉取Debian 9.2的镜像 docker pull debian:9.2,然后运行 docker run 6d83de432e98 ping baidu.com。进入系统中查看用户分组 cat /etc/group

root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
kmem:x:15:
dialout:x:20:
fax:x:21:
voice:x:22:
cdrom:x:24:
floppy:x:25:
tape:x:26:
sudo:x:27:
audio:x:29:
dip:x:30:
www-data:x:33:
backup:x:34:
operator:x:37:
list:x:38:
irc:x:39:
src:x:40:
gnats:x:41:
shadow:x:42:
utmp:x:43:
video:x:44:
sasl:x:45:
plugdev:x:46:
staff:x:50:
games:x:60:
users:x:100:
nogroup:x:65534:

上面就是debian镜像中的所有分组。

然后拉取apline 3.6 的镜像 docker pull alpine:3.6,并运行docker run 77144d8c6bdc ping baidu.com。进入系统查看用户分组

root:x:0:root
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
sys:x:3:root,bin,adm
adm:x:4:root,adm,daemon
tty:x:5:
disk:x:6:root,adm
lp:x:7:lp
mem:x:8:
kmem:x:9:
wheel:x:10:root
floppy:x:11:root
mail:x:12:mail
news:x:13:news
uucp:x:14:uucp
man:x:15:man
cron:x:16:cron
console:x:17:
audio:x:18:
cdrom:x:19:
dialout:x:20:root
ftp:x:21:
sshd:x:22:
input:x:23:
at:x:25:at
tape:x:26:root
video:x:27:root
netdev:x:28:
readproc:x:30:
squid:x:31:squid
xfs:x:33:xfs
kvm:x:34:kvm
games:x:35:
shadow:x:42:
postgres:x:70:
cdrw:x:80:
usb:x:85:
vpopmail:x:89:
users:x:100:games
ntp:x:123:
nofiles:x:200:
smmsp:x:209:smmsp
locate:x:245:
abuild:x:300:
utmp:x:406:
ping:x:999:
nogroup:x:65533:
nobody:x:65534:

在Debian系统中用www-data用户组中www-data用户跑php服务。产生一个socket文件 php7.sock 代替端口监听。这个文件被挂载到宿主机的目录上。OpenResty通过挂载目录到相同的宿主机目录上来设置监听。

通过编写编排文件docker-compose.yml文件,运行docker-compose up进行部署服务。php服务中会给php7.sock文件赋予 swr-wr----的权限,而该文件所属www-data:www-data。此时就会出现一个问题。在Debian中,该文件是www-data这个组中的用户可以读写的,但是在alpine中并没有这个www-data的用户组和这个用户。那他是怎么处理这个问题的呢?(在linux中的文件,是不可能没有所属用户和所属用户组的。) 观察Debian中的www-data的用户组列表,发现该组中的编号是33。在实际操作部署中,php7.sock文件是属于xfs:xfs,而Debian中的www-data的GID正好与alpine中的xfs的GID相同。

GID相同造成两个系统中的授权出现了不同,而(矫情的)sock文件只认www-data这个用户组中的用户,因此造成了OpenResty在有请求时监听sockt文件会出现没有权限读取的问题。

解决问题

既然docker跨系统的授权是通过GID配对,而sockt文件只认同名字用户组用户。因此需要删除xfs用户组创建www-data用户组。

deluser xfs && \
    addgroup -g 33 -S www-data && adduser -u 33 -D -S -G www-data www-data

编排代码

version: '2.0'
services:
  php-fpm:
    image: daocloud.io/xss_er/php:php72
    container_name: php72
    restart: always
    ports:
      - "9000"
    volumes:
      - ./code:/var/www/app #work dir
      - /tmp/test/php7-fpm:/var/run/php7-fpm
    networks:
      - back-net
  nginx:
    image: daocloud.io/xss_er/nginx:openresty-server
    container_name: openresty
    restart: always
    ports:
      - "15000:80"
    volumes:
      - ./data/wwwlog:/usr/local/openresty/nginx/logs #logfile dir
      - /tmp/test/php7-fpm:/var/run/php7-fpm
      - ./code:/var/www/app #Code
      - ./conf.d:/usr/local/openresty/nginx/conf/conf.d
    networks:
      - back-net
networks:
  back-net:
    external: true

相关git:https://gitee.com/jinfeijie/dockerService

发表评论

电子邮件地址不会被公开。 必填项已用*标注