如果在Docker容器中执行,os.getlogin()
将抛出一个FileNotFoundError: [Errno 2] No such file or directory
。
我知道Python文档建议使用不同的方法,但在某些代码中,我不能简单地更改它。
我使用的是ubuntu22.04和python 3.10.6 (都在Docker容器中)。
我是托管从Windows 10与码头桌面和WSL2。
这是一辆MWE:
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y \
python3
构建并运行它时:
docker build -t mwe .
docker run -it mwe
然后在Docker容器中执行以下操作:
python3 -c "import os; print(os.getlogin())"
它会抛出错误:
Traceback (most recent call last):
File "<string>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory
有什么好办法来避免这个错误吗?
发布于 2022-10-25 01:38:03
这在一定程度上是Python os.getlogin问题的重复,但答案并没有真正找到问题的根源。
这是而不是的问题。我们可以用最小的C程序来再现相同的行为:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char *login = getlogin();
if (login == NULL) {
perror("getlogin");
exit(1);
}
printf("login: %s\n", login);
exit(0);
}
如果在容器中运行此操作,您将得到输出:
getlogin: No such device or address
通过glibc源代码来跟踪这个错误,错误来自getlogin代码,但实际上是由__getlogin_r_loginuid
中的代码引起的。
if (uid == (uid_t) -1)
{
__set_errno (ENXIO);
return ENXIO;
}
我们点击这个代码是因为/proc/self/loginuid
的值是:
$ cat /proc/self/loginuid
4294967295
其中4294967295
只是-1
,在本例中这意味着“未初始化此值”,这是因为我们没有通过通常为我们设置的任何类型的登录管理器输入这个shell。
对于一个简单的解决方法,我们只需将当前的UID写入该文件:
root@d4da9e11f42e:~# python3 -c 'import os; print(os.getlogin())'
Traceback (most recent call last):
File "<string>", line 1, in <module>
OSError: [Errno 6] No such device or address
root@d4da9e11f42e:~# echo $UID > /proc/self/loginuid
root@d4da9e11f42e:~# python3 -c 'import os; print(os.getlogin())'
root
这将是相对容易烘焙进入您的容器启动。
另一种选择是对os
模块进行猴子标记,以便用其他东西(如getpass.getuser()
)替换os.getlogin
。
听起来好像WSL没有提供loginuid
特性。
这个答案仍然准确地指出了问题所在:getlogin()
无法读取loginuid
文件,并且您得到了相同的错误(您可以在__getlogin_r_loginuid
实现的前面看到代码路径)。
如果您的内核没有提供这个特性,那么您唯一的真正选择就是修复代码--要么修改对os.getlogin()
的调用,要么在遗留代码调用os.getlogin()
之前安排对os.getlogin()
模块进行猴子加密。
一个稍微不那么正统的选择是使用函数插入来覆盖getlogin
库调用。
从C
中的最小fake_getlogin.c
代码开始
char *getlogin(void) {
return "root";
}
将其编译到共享库:
gcc -fPIC -c fake_getlogin.c
ld -o fake_getlogin.so -shared fake_getlogin.o
将其嵌入到Dockerfile中,并安排通过/etc/ld.so.preload
预加载它
FROM ubuntu:22.04
RUN DEBIAN_FRONTEND=noninteractive \
apt-get update && \
apt-get install -y \
python3
COPY fake_getlogin.so /lib/fake_getlogin.so
RUN echo /lib/fake_getlogin.so > /etc/ld.so.preload
现在,重新尝试您的原始复制器,您会发现它运行时没有错误:
root@4c86cde47db1:/# python3 -c 'import os; print(os.getlogin())'
root
这假设没有更多特定于WSL的怪癖需要克服。
如果您决定在实践中使用函数插入解决方案,您可能应该安排将构建共享库作为映像构建过程的一部分;例如:
FROM ubuntu:22.04 AS builder
RUN DEBIAN_FRONTEND=noninteractive \
apt-get update && \
apt-get install -y \
build-essential
WORKDIR /src
COPY fake_getlogin.c ./
RUN gcc -fPIC -c fake_getlogin.c && \
ld -o fake_getlogin.so -shared fake_getlogin.o
FROM ubuntu:22.04
COPY --from=builder /src/fake_getlogin.so /lib/fake_getlogin.so
RUN DEBIAN_FRONTEND=noninteractive \
apt-get update && \
apt-get install -y \
python3
RUN echo /lib/fake_getlogin.so > /etc/ld.so.preload
https://stackoverflow.com/questions/74187896
复制相似问题