在 ubuntu 终端中,我运行:
sudo strace -f -p `pidof containerd` -o strafce_log
在另一个终端我运行
docker run ubuntu
结果,两个终端都挂了:(如果我停止docker服务,那么我就无法再启动它了
容器保持状态created
,并且我对其发出的任何命令都会挂起( docker logs
,, )docker rm
system prune
针对其他容器或镜像的 Docker 命令运行良好。 Docker ps 也可以工作
我还在网上发现我应该看看cat /var/log/syslog | grep docker
。不幸的是那里也什么也没有。
您能指导我在哪里可以获得更多日志或有关 docker 或该容器在做什么的一些信息吗?
答案1
对 生成的日志的分析sudo strace -ff -p $(pidof containerd) -o strace_log
表明,当execve()
名为 的进程调用时,它会停止runc init
。这让我runc GH 页面上的此错误报告这解释了这是一个内核错误,每个使用 pthread 的程序都可以重现该错误,并execve()
提供了一个可用于重现该问题的简短 Go 程序:
package main
import (
"os"
"syscall"
)
func main() {
syscall.Exec("/bin/echo", []string{"/bin/echo", "Hello"}, os.Environ())
}
知道这是一个内核错误,我使用 Raspberry Pi 进行测试,这样我就可以快速构建和替换 Linux 内核,而不会冒使我的主机无法启动或使用虚拟机的风险,并且由于 Raspbian 中默认情况下未安装 Go,所以我使用了以下 C 程序供测试用:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
void *foo(void *p)
{
(void) p;
while(1)
{
puts("in thread");
sleep(2);
}
}
int main(void)
{
printf("pid: %jd\n", (intmax_t) getpid());
pthread_t tid;
pthread_create(&tid, NULL, foo, NULL);
char *envp[] = {"var"};
char *ls_args[] = { "/bin/ls" , "-l", NULL};
if (execve(ls_args[0], ls_args, envp) < 0) {
perror("execve error");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
构建gcc strace-test.c -o strace-test -pthread
并查看它
strace -f ./strace-test
是否也会被卡住。
原本应该修复 strace 的补丁已于 2016 年发送到 Linux 内核邮件列表
但它尚未被接受,您可以阅读整个讨论以了解原因。尽管如此,我还是将这个补丁应用到了我的本地
Raspberry Pi 的 Linux 内核树针对 rpi-5.6.y 分支,在 Raspberry Pi 上重建和替换内核后,strace -f ./strace-test
不再卡住。自 2016 年以来,Linux 源代码发生了一些变化,补丁并没有完全应用。 FWIW,我应用的完整补丁是:
diff --git a/kernel/fork.c b/kernel/fork.c
index 60a1295..c26aaa1 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1224,7 +1224,7 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
struct mm_struct *mm;
int err;
- err = mutex_lock_killable(&task->signal->cred_guard_mutex);
+ err = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
if (err)
return ERR_PTR(err);
diff --git a/kernel/signal.c b/kernel/signal.c
index 9ad8dea..ea7c7b5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -108,6 +108,10 @@ static bool sig_ignored(struct task_struct *t, int sig, bool force)
if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
return false;
+ /* Do not ignore signals sent from child to the parent */
+ if (current->ptrace && current->parent == t)
+ return 0;
+
/*
* Tracers may want to know about even ignored signal unless it
* is SIGKILL which can't be reported anyway but can be ignored