우분투 터미널에서 다음을 실행합니다.
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())
}
이것이 커널 버그라는 것을 알고 호스트가 부팅할 수 없거나 가상 머신을 사용할 수 없는 위험 없이 Linux 커널을 신속하게 빌드하고 교체할 수 있도록 테스트에 Raspberry Pi를 사용했으며 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