虽然 linux 有 user namespace 隔离技术,但是 docker 不支持类似 podman 那样的给每个容器设置范围性的 uidmap 映射(当然 k8s 现在也不支持),并且容器默认配置下的权限虽然去掉了一些。但是容器内还是能对挂载进去的进行修改的,比如帖子 rm -rf * 前一定一定要看清当前目录 老哥的操作:
1 2 3 4 5 6 7 8
docker run --rm -v /mnt/sda1:/mnt/sda1 -it alpine cp /mnt/sda1/somefile.tar.gz . tar xzvf somefile.tar.gz cd somefile-v1.0 ls # 看了看内容觉得不是自己想要的,回上一级目录准备删掉: cd .. rm -rf *
#!/bin/sh # 脚本某行报错就退出 set -e # 脚本的第一个参数为 -开头的字符串,或者是 .conf 结尾的字符串 if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then # 重新设置 $@ 为 redis-server "$@" set -- redis-server "$@" fi
# allow the container to be started with `--user` # 第一个参数为 redis-server 并且执行的用户为 root if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then # 更改当前目录下的 owner 为 redis find . \! -user redis -execchown redis '{}' + # 使用 gosu 切换到 redis 执行本脚本,并带上此刻的 $@参数 exec gosu redis "$0""$@" fi
# set an appropriate umask (if one isn't set already) # - https://github.com/docker-library/redis/issues/305 # - https://github.com/redis/redis/blob/bb875603fb7ff3f9d19aad906bd45d7db98d9a39/utils/systemd-redis_server.service#L37 um="$(umask)" if [ "$um" = '0022' ]; then umask 0077 fi
exec"$@"
例如下面执行流程:
1 2 3 4 5 6 7 8
$ docker run -d -name redis7 -v $PWD/redis-ctr-data:/data --net host redis:7 --port 7777 $ docker top redis7 UID PID PPID C STIME TTY TIME CMD systemd+ 1041135 1041116 1 15:47 ? 00:00:00 redis-server *:7777 $ docker exec redis7 id redis uid=999(redis) gid=999(redis) groups=999(redis) $ grep 999 /etc/passwd systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
funcmain() { // Find SMBIOS data in operating system-specific location. rc, ep, err := smbios.Stream() if err != nil { log.Fatalf("failed to open stream: %v", err) } // Be sure to close the stream! defer rc.Close()
// Decode SMBIOS structures from the stream. d := smbios.NewDecoder(rc) ss, err := d.Decode() if err != nil { log.Fatalf("failed to decode structures: %v", err) }
major, minor, _ := ep.Version()
for _, s := range ss { if s.Header.Type == 1 { d := s.Formatted // https://github.com/mirror/dmidecode/blob/dmidecode-3-5/dmidecode.c#L485 if major > 0x02 || (major == 0x02 && minor >= 0x06) { fmt.Printf("UUID: %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", d[7], d[6], d[5], d[4], d[9], d[8], d[11], d[10], d[12], d[13], d[14], d[15], d[16], d[17], d[18], d[19], ) } else { fmt.Printf("UUID: %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15], d[16], d[17], d[18], d[19], ) } } } }
if [ "$(stat -c %u "$CONSUL_DATA_DIR")" != "${CONSUL_UID}" ]; then chown ${CONSUL_UID}:${CONSUL_GID} "$CONSUL_DATA_DIR" fi
这里会存在一个问题,如果之前是覆盖了 entrypoint 使用 root 启动的,再切正确姿势下,因为 data 目录下子目录没被 chown,consul 在 data 下子目录写入 node-id 会报错没权限,所以我是这样 hack 重做镜像的:
1 2 3 4 5
ARG VER=1.8.3 FROM consul:${VER} RUN sed -ri -e 's/(chown)(\s+consul:)/\1 -R\2/' \ -e '1s@/usr/bin/dumb-init\s+@@' \ /usr/local/bin/docker-entrypoint.sh