最近公司 CI 升级,将 docker 基镜像由原先的 debian 切换到了 ubuntu,导致应用一旦成功启动之后,再次执行重启将会持续失败。查看日志,发现打印 ln: failed to access '/tmp/access.log/stdout': Not a directory
看来是 ln
执行失败,导致 docker entrypoint 无法执行成功,所以一直 restarting,查看其 entrypoint.sh
检查 ln
相关逻辑:ln -sf /dev/stdout /tmp/access.log
似乎并没有问题,那为啥后面几次执行会把 access.log
识别为一个目录呢?奇怪的是,debian 镜像就没有这个问题:
$ docker run -it --rm debian:10 bash
> ln -s /dev/stdout /tmp/access.log
> ln -s /dev/stdout /tmp/access.log
> exit
$ docker run -it --rm ubuntu:22.04 bash
> ln -s /dev/stdout /tmp/access.log
> ln -s /dev/stdout /tmp/access.log
ln: failed to access '/tmp/access.log/stdout': Not a directory
更为魔幻的是,同事们纷纷表示本地无法复现,只有我的开发环境有这个问题。无奈,只能寄希望于 strace
找到一些蛛丝马迹:
$ docker run --privileged -it --rm ubuntu:22.04 bash
> apt-get update && apt-get install strace
> ln -sf /dev/stdout /tmp/access.log
> strace ln -sf /dev/stdout /tmp/access.log
...
symlinkat("/dev/stdout", AT_FDCWD, "/tmp/access.log") = -1 EEXIST (File exists)
openat(AT_FDCWD, "/tmp/access.log", O_RDONLY|O_PATH|O_DIRECTORY) = 3
symlinkat("/dev/stdout", 3, "stdout") = -1 ENOTDIR (Not a directory)
newfstatat(3, "stdout", 0x7fffcaf03a90, AT_SYMLINK_NOFOLLOW) = -1 ENOTDIR (Not a directory)
write(2, "ln: ", 4ln: )
...
有意思的地方出现了,openat(AT_FDCWD, "/tmp/access.log", O_RDONLY|O_PATH|O_DIRECTORY) = 3
表示将 /tmp/access.log
按照目录打开。理论上应该返回 -1
才对,但我这里却返回了 3
表示可以成功打开,也就是当真把 /tmp/access.log
识别成了一个目录。但是在同事们的环境中,却真真实实的返回了 openat(AT_FDCWD, "/tmp/access.log", O_RDONLY|O_PATH|O_DIRECTORY) = -1 ENOTDIR (Not a directory)
经询问,大家使用的内核都是 5.x,而只有我的环境用的是 3.10