Back to questions
СБЕР
Senior
4
Как реализуется изоляция контейнеров на уровне ядра Linux? Расскажите подробнее про namespaces
Companies where asked
Answer from AI
sobes.tech AI
Изоляция контейнеров в Linux достигается с помощью механизма namespaces — это особенность ядра, которая позволяет создавать отдельные пространства имён для различных системных ресурсов. Каждый namespace изолирует определённый аспект окружения процесса, например:
- PID namespace — изолирует идентификаторы процессов, так что процессы в одном namespace видят только свои PID.
- Mount namespace — изолирует точки монтирования файловой системы, позволяя контейнеру иметь собственную файловую структуру.
- Network namespace — изолирует сетевые интерфейсы и настройки, создавая отдельный сетевой стек.
- UTS namespace — изолирует hostname и domain name.
- IPC namespace — изолирует межпроцессное взаимодействие.
- User namespace — изолирует идентификаторы пользователей и групп, позволяя контейнеру иметь свои UID/GID.
Когда создаётся контейнер, ядро создаёт для него набор таких namespaces, благодаря чему процессы внутри контейнера видят только своё окружение и не влияют на процессы вне контейнера. Это обеспечивает безопасность и изоляцию.
Пример создания нового PID namespace в Go с использованием syscall:
package main
import (
"fmt"
"syscall"
"os"
)
func main() {
cmd := os.Args[0]
if len(os.Args) > 1 && os.Args[1] == "child" {
fmt.Printf("[child] PID: %d\n", syscall.Getpid())
select {} // ждем
} else {
fmt.Printf("[parent] PID: %d\n", syscall.Getpid())
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
Sys: &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWPID,
},
}
pid, err := syscall.ForkExec(cmd, []string{cmd, "child"}, attr)
if err != nil {
panic(err)
}
fmt.Printf("Запущен процесс с новым PID namespace, PID: %d\n", pid)
}
}
Этот пример демонстрирует создание процесса с новым PID namespace, где у дочернего процесса будет свой набор PID, изолированный от родительского пространства.