Контейнеризация
| Принцип | изоляция процессов на общем ядре ОС |
|---|---|
| Механизмы Linux | namespaces, cgroups, capabilities, seccomp, overlay-файловые системы |
| Предшественники | chroot (1979), FreeBSD jails (2000), Solaris Zones (2004), LXC (2008) |
| Массовое распространение | Docker (2013) |
| Стандарт | Open Container Initiative (OCI, с 2015) |
| Оркестрация | Kubernetes, Docker Swarm, Nomad |
| Инструменты | Docker, Podman, containerd, CRI-O |
Контейнеризация — способ упаковать приложение вместе с его зависимостями (библиотеками, интерпретатором, конфигурацией) в контейнер — изолированную среду, которая одинаково запускается на ноутбуке разработчика, тестовом сервере и в облаке. В отличие от виртуальной машины, контейнер не содержит собственного ядра операционной системы: все контейнеры на хосте используют общее ядро, а изоляция обеспечивается его механизмами. Поэтому контейнеры запускаются за доли секунды и расходуют мало ресурсов.
Контейнеры — основа современной разработки и эксплуатации: приложения поставляются как образы Docker, собираются по Dockerfile, запускаются локально через Docker Compose и в продакшене — под управлением Kubernetes.
Зачем нужны контейнеры
- «У меня работает». Образ содержит всё нужное приложению, поэтому разница между средами разработки и продакшена исчезает.
- Изоляция зависимостей. На одном сервере уживаются сервисы с несовместимыми версиями Python, библиотек и системных пакетов.
- Плотность и скорость. Десятки контейнеров на одном сервере вместо нескольких виртуальных машин; запуск — за секунды.
- Неизменяемость. Образ собирается один раз и разворачивается без изменений; обновление — это замена контейнера новым, а откат — запуск предыдущей версии образа.
- Единый формат поставки для CI/CD, облаков и оркестраторов.[4]
Контейнеры и виртуальные машины
| Виртуальная машина | Контейнер | |
|---|---|---|
| Что виртуализируется | оборудование | окружение процесса |
| Ядро ОС | своё в каждой ВМ | общее с хостом |
| Размер образа | гигабайты | мегабайты — сотни мегабайт |
| Запуск | десятки секунд — минуты | доли секунды |
| Изоляция | сильная (гипервизор) | слабее (общее ядро) |
| Другая ОС | любая | только совместимая с ядром хоста |
Контейнер Linux нельзя напрямую запустить на ядре Windows или macOS — Docker Desktop на этих системах тайно запускает небольшую виртуальную машину с Linux. Если нужна более сильная изоляция, используют гибриды: gVisor перехватывает системные вызовы, а Kata Containers и Firecracker запускают каждый контейнер в лёгкой виртуальной машине.
Как устроен контейнер в Linux
Контейнер — это обычный процесс, на который ядро наложило ограничения (см. Namespaces и cgroups):
- Namespaces (пространства имён) ограничивают то, что процесс видит: собственное дерево процессов (PID), сетевые интерфейсы (net), точки монтирования (mnt), имя хоста (UTS), пользователей (user), IPC.[1]
- Cgroups (контрольные группы) ограничивают то, сколько процесс потребляет: память, процессор, ввод-вывод, число процессов.[2]
- Capabilities, seccomp, AppArmor/SELinux урезают привилегии: даже root внутри контейнера не может загружать модули ядра или менять системное время (см. Права доступа в Unix).
- Многослойная файловая система (overlayfs) собирает корневую ФС контейнера из слоёв образа, доступных только для чтения, и тонкого слоя для записи.
docker run --rm -it --memory 256m --cpus 0.5 alpine sh
# внутри: ps aux покажет только процессы контейнера, hostname — свой
История
Идея изоляции появилась задолго до Docker. Системный вызов chroot (Unix V7, 1979) подменял корневой каталог процесса. В 2000 году FreeBSD добавила jails — изолированные окружения с собственными пользователями и сетью,[5] в 2004 году Sun представила Solaris Zones. В Linux механизмы появлялись постепенно: namespaces с 2002 года, cgroups — разработка инженеров Google, вошедшая в ядро в 2008 году. В том же году появился LXC, собравший их в удобный инструмент.
Прорывом стал Docker (2013): он добавил простой формат образов со слоями, Dockerfile и публичный реестр Docker Hub, превратив контейнеры из инструмента администраторов в инструмент разработчиков. В 2014 году Google открыла Kubernetes, а в 2015 году индустрия создала Open Container Initiative (OCI), которая стандартизировала формат образов и среды выполнения, чтобы контейнеры не зависели от одного поставщика.[3]
Экосистема
| Слой | Что делает | Примеры |
|---|---|---|
| Сборка | образ по описанию | Docker Build (BuildKit), Buildah, kaniko |
| Хранение | реестр образов | Docker Hub, GitHub Container Registry, Harbor (см. Container registry) |
| Запуск низкого уровня | создаёт процесс с namespaces и cgroups | runc, crun |
| Среда выполнения | управляет образами и контейнерами | containerd, CRI-O |
| Инструменты разработчика | CLI и локальная работа | Docker, Podman, nerdctl |
| Оркестрация | кластер, масштабирование, самовосстановление | Kubernetes, Nomad, Docker Swarm |
Формат описан в статье Образ контейнера и OCI. Kubernetes с 2022 года работает с containerd или CRI-O напрямую, без Docker, но образы, собранные Docker, остаются совместимыми благодаря OCI.[6]
Хорошие практики
- Один процесс (одна ответственность) на контейнер; логи — в стандартный вывод.
- Минимальные базовые образы (
alpine,distroless,-slim) и многоэтапная сборка — меньше размер и поверхность атаки. - Запуск не от root, файловая система только для чтения, где возможно.
- Никаких секретов внутри образа: их передают через переменные окружения или хранилища секретов.
- Состояние — в томах или внешних сервисах; сам контейнер можно в любой момент удалить и пересоздать.