Docker 容器挂起状态为“已创建”

Docker 容器挂起状态为“已创建”

在 ubuntu 终端中,我运行:

sudo strace -f -p `pidof containerd` -o strafce_log

在另一个终端我运行

docker run ubuntu

结果,两个终端都挂了:(如果我停止docker服务,那么我就无法再启动它了

容器保持状态created,并且我对其发出的任何命令都会挂起( docker logs,, )docker rmsystem 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

相关内容