镜像构建时
USER指令
Dockerfile的USER指令,用来指定Dockerfile里某些指令运行的账户,官方解释如下:
The USER instruction sets the user name or UID to use when running the image and for any RUN, CMD and ENTRYPOINT instructions that follow it in the Dockerfile.
主要意思是说USER指令用来设定用户名或者uid,用以运行镜像,或者Dockerfile中紧随该指令之后的RUN/CMD/ENTRYPOINT。
如下Dockerfile,表示使用work账户运行后续的RUN/CMD/ENTRYPOINT指令,USER指令之前的依然使用之前设定的,或者基础镜像中设定的用户
FROM centos:latest
RUN mkdir /home/work/logdata
USER work
RUN echo "hello world" > /home/work/logdata/a.log
注意下面几点
- 默认使用root账户,也仅有root账户
- 基础镜像里设定的账户可以继承,直到遇到下一条USER指令
- 使用USER指令前,必须确保要设定的账户已经存在
- 切忌在Dockerfile里频繁切换账户,会带来存储效率的损失
关于ADD/COPY到镜像里的文件
使用ADD、COPY指令添加到镜像里的文件,默认的owner和group都是root,且这两条指令必须使用root账户才能运行,故如果需要非root账户能够使用COPY、ADD进去的文件,则需要更改文件的owner,甚至group。
FROM centos:latest
RUN mkdir /home/work/logdata
COPY server.conf /home/work/server.conf
USER work
RUN echo "hello world" > /home/work/logdata/a.log && \
chown -R work:work /home/work/server.conf
容器运行时
如若在ENTRYPOINT中需要指定运行命令的用户,官方建议用gosu代替sudo可以避免某些信号处理上的边界条件。不过这些边界条件比较罕见。
官方给出了一个例子,如下所示
#!/bin/bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
上面的脚本中,docker run指定的命令会以postgres用户的身份执行。
镜像默认的ENTRYPOINT为/bin/sh -c,通过docker run或CMD指定的命令会作为ENTRYPOINT的参数执行。举个例子,docker run ubuntu:latest ls就是执行/bin/sh -c ls。有些时候我们需要指定ENTRYPOINT的值,比如换成自己的包装脚本。
为什么要用gosu,而不是sudo,主要sudo有两个缺点
- sudo会作为被授权的命令的父进程一直存在,直到该命令退出。
- sudo模式下的HOME环境变量仍是用sudo者原来的值。