> Как происходит работа с дескрипторами процессов внутри контейнеров и есть ли доступ к дескрипторам хостовой машины (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: YADRO

Стек: Go

> Пример ответа

Короткий ответ

Внутри контейнера процессы видят собственную изолированную PID namespace, поэтому дескрипторы процессов (PID) не совпадают с хостовыми. Доступа к дескрипторам хостовой машины из контейнера нет - это обеспечивается изоляцией namespace и capabilities. Однако при определённых условиях (privileged mode, монтирование /proc, общие PID namespace) доступ возможен, что создаёт риски безопасности. В Go работа с процессами обычно идёт через syscall или os/exec, но в контейнере вы ограничены своей namespace.

Подробное объяснение

Контейнеры используют Linux namespaces для изоляции. PID namespace - ключевой механизм: каждый контейнер получает собственную нумерацию процессов, начиная с PID 1 (обычно init-процесс). Это означает, что процесс с PID 42 внутри контейнера может иметь PID 12345 на хосте.

Доступ к хостовым процессам из контейнера по умолчанию закрыт:

  • /proc внутри контейнера показывает только процессы своей namespace
  • syscall kill(), getpid(), waitpid() работают в рамках текущей namespace
  • отсутствие CAP_SYS_PTRACE и CAP_SYS_ADMIN блокирует ptrace и другие операции

Исключения, когда доступ появляется:

  • privileged контейнер (--privileged) - получает все capabilities и доступ к хостовым namespace
  • монтирование хостового /proc (например, bind mount)
  • запуск контейнера с --pid=host - разделяет PID namespace с хостом
  • наличие CAP_SYS_PTRACE позволяет ptrace процессов в своей namespace, но не на хосте

В Go работа с процессами через os/exec или syscall использует системные вызовы, которые автоматически работают в текущей namespace процесса. Go runtime не даёт прямого доступа к хостовым PID, если вы не находитесь в общей namespace.

На практике

Для backend-разработчика на Go важно понимать:

  • os.FindProcess(pid) не проверяет существование процесса, а только создаёт объект - сигналы будут отправлены в рамках текущей namespace
  • syscall.Kill(pid, sig) вернёт ESRCH, если процесса нет в вашей namespace
  • чтение /proc/pid/... внутри контейнера ограничено вашей namespace
  • для мониторинга хостовых процессов из контейнера нужны специальные привилегии или sidecar-подход

Если вам нужно управлять хостовыми процессами из контейнера - это архитектурный анти-паттерн. Лучше использовать API хоста или запускать агента на хосте.

Пример кода

GO
package main
import (
"fmt"
"os"
"syscall"
)
func main() {
// Попытка отправить сигнал процессу с PID 1
// В контейнере это init-процесс контейнера, на хосте - systemd
proc, err := os.FindProcess(1)
if err != nil {
fmt.Println("FindProcess error:", err)
return
}
// Сигнал 0 используется для проверки существования процесса
err = proc.Signal(syscall.Signal(0))
if err != nil {
fmt.Println("Signal error:", err)
// В контейнере без прав будет EPERM или ESRCH
return
}
fmt.Println("Process 1 exists in current namespace")
// Чтение /proc/1/status покажет информацию о процессе
// в текущей namespace, а не о хостовом PID 1
data, err := os.ReadFile("/proc/1/status")
if err != nil {
fmt.Println("Read /proc error:", err)
return
}
fmt.Println(string(data[:200]))
}

Как отвечать на собеседовании

Начните с чёткого разделения: PID namespace изолирует процессы, и по умолчанию контейнер не видит хостовые PID. Упомяните, что /proc - это виртуальная файловая система, которая отражает текущую namespace. Затем перечислите исключения (privileged, --pid=host, монтирование /proc) и объясните, почему это опасно. Покажите понимание, как это работает в Go: системные вызовы автоматически работают в текущей namespace, и нет специального API для доступа к хостовым процессам. Если спросят про безопасность - подчеркните, что доступ к хостовым PID означает фактически полный контроль над хостом.

Что проверяет интервьюер

  • понимание концепции namespaces и их роли в контейнеризации
  • знание, как /proc связан с PID namespace
  • осознание различий между PID внутри контейнера и на хосте
  • понимание ограничений и исключений (privileged mode, capabilities)
  • практические знания работы с процессами в Go (os, syscall)
  • способность оценить риски безопасности при доступе к хостовым процессам

Типичные ошибки

  • утверждение, что контейнер вообще не может видеть хостовые процессы - это неверно при privileged mode или --pid=host
  • путаница между PID namespace и другими namespace (mount, network)
  • предположение, что os.FindProcess(pid) проверяет существование процесса - это не так, он просто создаёт объект
  • игнорирование роли capabilities (CAP_SYS_PTRACE, CAP_SYS_ADMIN) в доступе к процессам
  • непонимание, что /proc - это не реальная файловая система, а динамическое представление, зависящее от namespace
  • рекомендация использовать ptrace из контейнера для хостовых процессов без упоминания ограничений

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью