Изображение


Содержание


1. Введение: Docker и Podman в 2026 году
2. Архитектура: daemon vs daemonless модель
3. Установка Docker и Podman: пошаговое руководство
4. Основные команды: полная совместимость CLI
5. Безопасность: rootless контейнеры и привилегии
6. Производительность и потребление ресурсов
7. Работа с Pod: концепция и практическое применение
8. Docker Compose vs Podman Compose
9. Networking: сети, DNS и коммуникация
10. Volumes и управление данными контейнеров
11. Оркестрация с Kubernetes и OpenShift
12. Практические сценарии: когда выбрать Docker, когда Podman
13. Пошаговая миграция с Docker на Podman
14. Часто задаваемые вопросы (FAQ)
15. Заключение и рекомендации для 2026



Введение: Docker и Podman в 2026 году


Docker революционизировал разработку программного обеспечения в 2013 году, когда Solomon Hykes представил концепцию лёгких контейнеров, основанных на Linux namespaces и cgroups. За 13 лет Docker стал глобальным стандартом в DevOps и разработке. Миллионы разработчиков по всему миру начинают свой путь в контейнеризации именно с Docker.

Однако к 2026 году ландшафт контейнеризации существенно изменился. Появились альтернативы, требования безопасности ужесточились, новые платформы (особенно Kubernetes) стали доминировать. Red Hat запустила проект Podman в 2018 году как открытую альтернативу Docker. За восемь лет этот инструмент созрел и обрел практические преимущества, которые делают его привлекательным для энтерпрайз-среды, финансовых учреждений и высоконагруженных систем.

Но это не простой выбор между хорошим и плохим инструментом. Обе платформы имеют свои сильные и слабые стороны, и выбор зависит от конкретного проекта, требований безопасности, размера команды и стратегических целей организации.

Почему этот вопрос актуален в 2026 году:

1. Kubernetes стал стандартом де-факто — большинство компаний и стартапов переходят на Kubernetes для управления контейнерами. Docker и Podman оба работают с Kubernetes, но интеграция различается.

2. Требования безопасности ужесточились — компании, работающие в финансовом секторе, государственных учреждениях и других высокосекурных окружениях, требуют меньше привилегий для разработчиков и инженеров. Podman изначально разработан с учётом этих требований.

3. Лицензирование Docker Desktop изменилось — Docker перешёл на пятидневную бесплатную пробу для коммерческих компаний, что привело к переосмыслению инструментов.

4. OpenShift популяризируется — Red Hat OpenShift (платформа, построенная на Kubernetes и использующая Podman) быстро завоёвывает рынок, особенно в финансовом и государственном секторе.

5. Локальная разработка изменилась — разработчики часто работают на более слабом оборудовании (тонкие ноутбуки, MacBook Air), и Podman экономит ресурсы лучше чем Docker.

В этом руководстве мы проведём честное, основанное на фактах сравнение Docker и Podman. Вы не найдёте здесь маркетинговых преувеличений. Вместо этого мы разберём:

- Архитектурные различия и их практическое значение
- Реальные цифры производительности
- Безопасность в различных сценариях
- Как выбрать правильный инструмент для вашего проекта
- Как безопасно мигрировать, если это необходимо

Руководство рассчитано на DevOps инженеров, системных администраторов, разработчиков и технических лидеров, которые работают с контейнерами и хотят принять обоснованное решение.



Архитектура: daemon vs daemonless модель


Архитектурное различие между Docker и Podman — это фундамент для понимания всех остальных различий. Это влияет на безопасность, производительность, масштабируемость и повседневное использование.

Docker: модель daemon-client архитектура

Docker состоит из двух основных компонентов: Docker daemon (dockerd) и Docker CLI (клиент).

Когда вы вводите команду `docker run -d nginx:latest`, эта команда не создаёт контейнер напрямую. Вместо этого Docker CLI отправляет запрос к Docker daemon через Unix socket (обычно `/var/run/docker.sock`) или TCP соединение.

Docker daemon получает этот запрос и выполняет всю тяжёлую работу:
- Создаёт Linux namespaces (изоляция процессов, файловой системы, сети)
- Настраивает cgroups (ограничения на ресурсы: CPU, память, I/O)
- Монтирует файловые системы (overlay filesystem для слоёв образа)
- Настраивает сетевые интерфейсы и правила iptables для маршрутизации трафика
- Запускает процесс внутри контейнера

Критически важный момент: Docker daemon работает с правами root (суперпользователя). Это необходимо, потому что все перечисленные операции требуют привилегий kernel'я.

text
┌──────────────────────────────┐
│ Пользователь разработчик │
│ $ docker run nginx:latest │
└──────────┬───────────────────┘

v
┌──────────────────────────────┐
│ Docker CLI │
│ Отправляет запрос по socket │
└──────────┬───────────────────┘
│ /var/run/docker.sock
v
┌──────────────────────────────┐
│ Docker Daemon (работает как │
│ root в системе) │
│ - Создает namespaces │
│ - Создает cgroups │
│ - Настраивает сеть │
│ - Запускает контейнер │
└──────────────────────────────┘


Преимущества daemon архитектуры Docker:
- Централизованное управление: один daemon может управлять всеми контейнерами в системе
- Оптимизация ресурсов: daemon может оптимизировать использование памяти, сетевых интерфейсов и дискового пространства на системном уровне
- Богатая функциональность: новые функции добавляются на уровне daemon'а без изменения CLI
- Зрелость и стабильность: Docker долго на рынке, решены многие проблемы

Недостатки daemon архитектуры Docker:
- Безопасность: если Docker daemon скомпрометирован, скомпрометирована вся система (daemon работает как root)
- Точка отказа: если daemon падает или перезагружается, все контейнеры теряют управление (хотя они продолжают работать)
- Привилегии: требует работы с root'ом или добавления пользователей в группу docker
- Одна точка контроля: проблема с daemon'ом влияет на все контейнеры

Podman: daemonless архитектура

Podman разработан с принципиально иным подходом. Вместо центрального daemon'а, который управляет всеми контейнерами, Podman использует модель, где каждый контейнер управляется непосредственно командой пользователя.

Когда вы вводите `podman run -d nginx:latest`, эта команда напрямую создаёт контейнер, используя те же Linux primitives (namespaces и cgroups), что использует Docker, но без промежуточного daemon'а.

Важное уточнение: в Podman есть фоновые процессы, но они используются для конкретных функций (управление сетью, мониторинг), а не как центральный управляющий daemon.

text
┌──────────────────────────────┐
│ Пользователь разработчик │
│ $ podman run nginx:latest │
└──────────┬───────────────────┘

v
┌──────────────────────────────┐
│ Podman (процесс пользователя)│
│ Непосредственно создает │
│ - Namespaces (через user NS) │
│ - Cgroups (в user namespace) │
│ - Сеть (через helpers) │
│ - Запускает контейнер │
└──────────────────────────────┘

v
┌──────────────────────────────┐
│ Контейнер (процесс │
│ пользователя на хост-системе)│
│ uid=0 в container = uid=100k+│
│ на хост-системе │
└──────────────────────────────┘


Ключевая особенность Podman: использование user namespaces для rootless режима. Контейнер видит себя работающим от root'а (потому что это root внутри user namespace'а), но на хост-системе это обычный процесс пользователя с малыми привилегиями.

Преимущества daemonless архитектуры Podman:
- Высокая безопасность: компрометация одного контейнера не влияет на другие контейнеры или хост-систему
- Нет центральной точки отказа: каждый контейнер независим
- Rootless по умолчанию: может работать как обычный пользователь без привилегий
- Меньше зависимостей: не требует постоянно работающего daemon'я
- Лучше интегрируется с systemd: контейнеры можно управлять как systemd сервисы

Недостатки daemonless архитектуры Podman:
- Сложнее реализовать некоторые функции (например, живую миграцию контейнеров между хост'ами)
- Потенциально меньше возможностей для оптимизации на системном уровне
- Может быть медленнее в определённых сценариях с очень большим количеством контейнеров

Практическое значение для разных сценариев

Архитектурное различие приводит к практическим последствиям:

Для безопасности: на Docker если один контейнер скомпрометирован и использует kernel exploit для выхода из контейнера, он получает доступ к daemon'у (работает как root). На Podman контейнер остаётся в user namespace'е даже при успешном escape'е.

Для привилегий: Docker требует либо запуска всех команд с sudo, либо добавления пользователя в группу docker. Добавление в группу docker эквивалентно root доступу! Podman позволяет работать как обычный пользователь без каких-либо специальных прав.

Для масштабируемости: Docker daemon может стать bottleneck'ом при сотнях одновременно создаваемых контейнеров. Podman масштабируется лучше, потому что нет центрального bottleneck'а.

Для ресурсов: Docker daemon всегда находится в памяти (50-150 MB). Podman процессы создаются по требованию и удаляются после завершения контейнера.



Установка Docker и Podman: пошаговое руководство


Процесс установки существенно различается. Docker требует добавления репозитория и нескольких шагов. Podman часто уже в стандартных репозиториях.

Полная установка Docker на Ubuntu 22.04 LTS

bash
<h2 id="shag-1-obnovit-indeks-paketov">Шаг 1: Обновить индекс пакетов</h2>
sudo apt update

<h2 id="shag-2-ustanovit-zavisimosti-dlya-dobavleniya-repozitoriya">Шаг 2: Установить зависимости для добавления репозитория</h2>
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

<h2 id="shag-3-dobavit-gpg-klyuch-docker">Шаг 3: Добавить GPG ключ Docker</h2>
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

<h2 id="shag-4-dobavit-repozitoriy-docker">Шаг 4: Добавить репозиторий Docker</h2>
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

<h2 id="shag-5-obnovit-indeks-paketov-eschyo-raz">Шаг 5: Обновить индекс пакетов ещё раз</h2>
sudo apt update

<h2 id="shag-6-ustanovit-docker-i-komponenty">Шаг 6: Установить Docker и компоненты</h2>
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

<h2 id="shag-7-zapustit-docker-daemon-i-vklyuchit-v-avtozagruzku">Шаг 7: Запустить Docker daemon и включить в автозагрузку</h2>
sudo systemctl start docker
sudo systemctl enable docker

<h2 id="shag-8-proverit-ustanovku">Шаг 8: Проверить установку</h2>
docker --version
docker run hello-world


Важное замечание о безопасности Docker

Чтобы работать с Docker без постоянного использования sudo, люди часто добавляют пользователя в группу docker:

bash
sudo usermod -aG docker $USER
newgrp docker


⚠️ Критически важно понять: это даёт пользователю эффективные привилегии root на системе!

Любой пользователь в группе docker может получить полный контроль над хост-системой:

bash
<h2 id="polzovatel-v-gruppe-docker-mozhet-vypolnit">Пользователь в группе docker может выполнить:</h2>
docker run -it -v /:/host ubuntu:22.04

<h2 id="vnutri-konteynera">Внутри контейнера:</h2>
cd /host
<h2 id="teper-polnyy-dostup-k-faylovoy-sisteme-kak-root">Теперь полный доступ к файловой системе как root</h2>
cat root/.ssh/id_rsa # Может украсть SSH ключ


Это не уязвимость Docker, а архитектурное проектное решение. Но это очень важно понимать и документировать.

Безопаснее использовать sudo с настройкой для выполнения docker команд без пароля:

bash
<h2 id="variant-1-prosto-ispolzovat-sudo">Вариант 1: Просто использовать sudo</h2>
sudo docker ps

<h2 id="variant-2-nastroit-sudo-bez-parolya-dlya-docker-komand">Вариант 2: Настроить sudo без пароля для docker команд</h2>
sudo visudo

<h2 id="dobavit-stroku">Добавить строку:</h2>
<h2 id="your-username-all-all-nopasswd-usr-bin-docker">your_username ALL=(ALL) NOPASSWD: /usr/bin/docker</h2>


Установка Podman на Ubuntu 22.04

bash
<h2 id="shag-1-obnovit-pakety">Шаг 1: Обновить пакеты</h2>
sudo apt update

<h2 id="shag-2-ustanovit-podman-i-podman-compose">Шаг 2: Установить Podman и Podman Compose</h2>
sudo apt install -y podman podman-compose

<h2 id="shag-3-proverit-ustanovku">Шаг 3: Проверить установку</h2>
podman --version
podman run hello-world # Работает без sudo!


Заметьте: Podman работает без sudo из коробки! Это потому что использует user namespaces.

Установка на CentOS / RHEL (Red Hat based)

Docker:
bash
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker


Podman (обычно уже в базовых репозиториях):
bash
sudo dnf install -y podman podman-compose
<h2 id="ili-na-centos-7">или на CentOS 7</h2>
sudo yum install -y podman podman-compose


Установка на Debian 11+

Docker:
bash
sudo apt update
sudo apt install -y docker.io docker-compose
sudo systemctl start docker
sudo systemctl enable docker


Podman:
bash
sudo apt update
sudo apt install -y podman podman-compose


Установка на Fedora

Podman встроен в Fedora (это окружение Red Hat):
bash
sudo dnf install -y podman podman-compose


Docker требует установки из репозитория (обычно не рекомендуется в Fedora, используйте Podman).

Проверка совместимости kernel'я

И Docker, и Podman полагаются на функции Linux kernel. Убедитесь, что ваше ядро поддерживает необходимые функции:

bash
<h2 id="proverit-nalichie-neobhodimyh-funktsiy-kernel-ya">Проверить наличие необходимых функций kernel&#039;я</h2>
grep CONFIG_NAMESPACES /boot/config-$(uname -r) # Должен быть y
grep CONFIG_CGROUPS /boot/config-$(uname -r) # Должен быть y
grep CONFIG_SECCOMP /boot/config-$(uname -r) # Должен быть y
grep CONFIG_NETFILTER /boot/config-$(uname -r) # Должен быть y

<h2 id="ili-prosto-poprobovat-zapustit-konteyner">Или просто попробовать запустить контейнер</h2>
podman run hello-world # Если работает, всё норм


Первоначальная настройка Podman для rootless режима

Для полной функциональности rootless режима может потребоваться дополнительная настройка:

bash
<h2 id="migratsiya-konfiguratsii-esli-trebuetsya">Миграция конфигурации (если требуется)</h2>
podman system migrate

<h2 id="proverit-status-rootless-rezhima">Проверить статус rootless режима</h2>
podman info | grep rootless
<h2 id="dolzhno-byt-rootless-true">Должно быть: rootless: true</h2>

<h2 id="proverit-uid-mapping">Проверить UID mapping</h2>
cat /etc/subuid
<h2 id="dolzhno-byt-chto-to-tipa-username-100000-65536">Должно быть что-то типа: username:100000:65536</h2>


Выбор версий для production (2026)

На 2026 год рекомендуемые версии:
- Docker: 24.x или выше (текущий стабильный канал), используйте LTS версии для production
- Podman: 4.x или выше (последние версии более стабильны)

Для production никогда не используйте `latest` тег — используйте конкретные версии, которые вы тестировали.

bash
docker --version  # Проверить текущую версию
podman --version




Основные команды: полная совместимость CLI


Один из главных преимуществ Podman для миграции — полная совместимость синтаксиса команд с Docker. Большинство docker команд можно выполнить с podman с минимальными изменениями.

Запуск и управление контейнерами

bash
<h2 id="zapustit-konteyner-v-background-e">Запустить контейнер в background&#039;е</h2>
docker run -d --name web -p 8080:80 nginx:latest
podman run -d --name web -p 8080:80 nginx:latest

<h2 id="zapustit-v-interaktivnom-rezhime">Запустить в интерактивном режиме</h2>
docker run -it ubuntu:22.04 /bin/bash
podman run -it ubuntu:22.04 /bin/bash

<h2 id="s-peremennymi-okruzheniya">С переменными окружения</h2>
docker run -d -e DATABASE_URL=postgres://host/db myapp:latest
podman run -d -e DATABASE_URL=postgres://host/db myapp:latest

<h2 id="s-ogranicheniyami-na-resursy">С ограничениями на ресурсы</h2>
docker run -d --memory=512m --cpus=1 myapp:latest
podman run -d --memory=512m --cpus=1 myapp:latest

<h2 id="s-montirovaniem-volume-ov">С монтированием volume&#039;ов</h2>
docker run -d -v /host/path:/container/path myapp:latest
podman run -d -v /host/path:/container/path myapp:latest

<h2 id="spisok-zapuschennyh-konteynerov">Список запущенных контейнеров</h2>
docker ps
podman ps

<h2 id="vse-konteynery-vklyuchaya-ostanovlennye">Все контейнеры (включая остановленные)</h2>
docker ps -a
podman ps -a

<h2 id="ostanovit-konteyner">Остановить контейнер</h2>
docker stop container-name
podman stop container-name

<h2 id="startovat-ostanovlennyy-konteyner">Стартовать остановленный контейнер</h2>
docker start container-name
podman start container-name

<h2 id="perezagruzit-konteyner">Перезагрузить контейнер</h2>
docker restart container-name
podman restart container-name

<h2 id="udalit-konteyner">Удалить контейнер</h2>
docker rm container-name
podman rm container-name

<h2 id="inspektirovat-konteyner-detalnaya-informatsiya">Инспектировать контейнер (детальная информация)</h2>
docker inspect container-name
podman inspect container-name

<h2 id="prosmotr-logov-konteynera">Просмотр логов контейнера</h2>
docker logs container-name
podman logs container-name

<h2 id="logi-v-rezhime-realnogo-vremeni">Логи в режиме реального времени</h2>
docker logs -f container-name
podman logs -f container-name

<h2 id="vypolnit-komandu-v-rabotayuschem-konteynere">Выполнить команду в работающем контейнере</h2>
docker exec -it container-name /bin/bash
podman exec -it container-name /bin/bash

<h2 id="skopirovat-fayl-iz-v-konteyner">Скопировать файл из/в контейнер</h2>
docker cp container-name:/path/to/file /local/path
podman cp container-name:/path/to/file /local/path


Работа с образами

bash
<h2 id="skachat-obraz-s-registry-ya">Скачать образ с registry&#039;я</h2>
docker pull ubuntu:22.04
podman pull ubuntu:22.04

<h2 id="spisok-vseh-obrazov-na-lokalnoy-mashine">Список всех образов на локальной машине</h2>
docker images
podman images

<h2 id="podrobnaya-informatsiya-ob-obraze">Подробная информация об образе</h2>
docker inspect image-name:tag
podman inspect image-name:tag

<h2 id="postroit-obraz-iz-dockerfile">Построить образ из Dockerfile</h2>
docker build -t my-image:1.0 .
podman build -t my-image:1.0 .

<h2 id="s-build-arguments">С build arguments</h2>
docker build --build-arg VERSION=1.0 -t my-image:1.0 .
podman build --build-arg VERSION=1.0 -t my-image:1.0 .

<h2 id="udalit-obraz">Удалить образ</h2>
docker rmi my-image:1.0
podman rmi my-image:1.0

<h2 id="otpravit-obraz-v-registry">Отправить образ в registry</h2>
docker push registry.company.com/my-image:1.0
podman push registry.company.com/my-image:1.0

<h2 id="sohranit-obraz-v-tar-arhiv-dlya-backup-ili-transfer-a">Сохранить образ в tar архив (для backup или transfer&#039;а)</h2>
docker save my-image:1.0 > my-image.tar
podman save my-image:1.0 > my-image.tar

<h2 id="zagruzit-obraz-iz-tar-arhiva">Загрузить образ из tar архива</h2>
docker load < my-image.tar
podman load < my-image.tar

<h2 id="teg-dlya-obraza">Тег для образа</h2>
docker tag my-image:1.0 my-image:latest
podman tag my-image:1.0 my-image:latest


Работа с сетями

bash
<h2 id="sozdat-novuyu-set">Создать новую сеть</h2>
docker network create my-network
podman network create my-network

<h2 id="spisok-setey">Список сетей</h2>
docker network ls
podman network ls

<h2 id="podrobnaya-informatsiya-o-seti">Подробная информация о сети</h2>
docker network inspect my-network
podman network inspect my-network

<h2 id="udalit-set">Удалить сеть</h2>
docker network rm my-network
podman network rm my-network

<h2 id="zapustit-konteyner-v-seti">Запустить контейнер в сети</h2>
docker run -d --network my-network --name app myapp:latest
podman run -d --network my-network --name app myapp:latest

<h2 id="podklyuchit-rabotayuschiy-konteyner-k-seti">Подключить работающий контейнер к сети</h2>
docker network connect my-network container-name
podman network connect my-network container-name

<h2 id="otklyuchit-konteyner-ot-seti">Отключить контейнер от сети</h2>
docker network disconnect my-network container-name
podman network disconnect my-network container-name


Работа с volumes

bash
<h2 id="sozdat-volume">Создать volume</h2>
docker volume create my-data
podman volume create my-data

<h2 id="spisok-volumes">Список volumes</h2>
docker volume ls
podman volume ls

<h2 id="informatsiya-o-volume">Информация о volume</h2>
docker volume inspect my-data
podman volume inspect my-data

<h2 id="udalit-volume">Удалить volume</h2>
docker volume rm my-data
podman volume rm my-data

<h2 id="ispolzovat-volume-pri-zapuske-konteynera">Использовать volume при запуске контейнера</h2>
docker run -d -v my-data:/data myapp:latest
podman run -d -v my-data:/data myapp:latest

<h2 id="bind-mount-montirovat-direktoriyu-host-sistemy">Bind mount (монтировать директорию хост-системы)</h2>
docker run -d -v /host/path:/container/path myapp:latest
podman run -d -v /host/path:/container/path myapp:latest


Различие в выводе команд

Хотя синтаксис идентичен, есть небольшие различия в выводе:

bash
<h2 id="docker-ps-pokazyvaet-tolko-konteynery-upravlyaemye-docker-daemon">docker ps показывает только контейнеры, управляемые Docker daemon</h2>
docker ps

<h2 id="podman-ps-pokazyvaet-konteynery-tekuschego-polzovatelya-po-umolchaniyu">podman ps показывает контейнеры текущего пользователя по умолчанию</h2>
podman ps

<h2 id="dlya-prosmotra-konteynerov-ot-root-v-podman">Для просмотра контейнеров от root в Podman:</h2>
sudo podman ps

<h2 id="dlya-prosmotra-vseh-konteynerov-vseh-polzovateley-v-podman">Для просмотра всех контейнеров всех пользователей в Podman:</h2>
podman ps --all --all-users


Использование Docker Compose файлов с обоими инструментами

Docker Compose файлы совместимы с обоими инструментами:

yaml
<h2 id="docker-compose-yml-rabotaet-s-docker-i-podman">docker-compose.yml (работает с Docker и Podman)</h2>
version: '3.8'

services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html

db:
image: postgres:15
environment:
POSTGRES_PASSWORD: mypassword
volumes:
- db_data:/var/lib/postgresql/data

volumes:
db_data:


Использование:

bash
<h2 id="docker">Docker</h2>
docker-compose up -d
docker-compose ps
docker-compose down

<h2 id="podman-trebuet-podman-compose-ustanovlen">Podman (требует podman-compose установлен)</h2>
podman-compose up -d
podman-compose ps
podman-compose down


Совместимость Docker API с Podman

Podman может работать совместимым с Docker API. Это позволяет использовать Docker инструменты с Podman:

bash
<h2 id="zapustit-podman-v-rezhime-sovmestimosti-s-docker">Запустить Podman в режиме совместимости с Docker</h2>
podman system service --time=0 unix:///run/podman/podman.sock &

<h2 id="v-drugom-terminale-ustanovit-peremennuyu-okruzheniya">В другом терминале установить переменную окружения</h2>
export DOCKER_HOST=unix:///run/podman/podman.sock

<h2 id="teper-docker-komandy-ispolzuyut-podman">Теперь docker команды используют Podman!</h2>
docker ps # Показывает Podman контейнеры
docker-compose up -d # Использует Podman вместо Docker


Это мощная функция, позволяющая постепенно мигрировать инструменты, которые зависят от Docker, на Podman.



Безопасность: rootless контейнеры и привилегии


Безопасность — это главная причина, по которой многие организации рассматривают переход с Docker на Podman. Особенно это касается финансовых учреждений, государственных структур и систем обработки чувствительных данных.

Docker и модель безопасности с привилегиями root

Docker daemon работает как root. Это имеет серьёзные следствия для безопасности:

1. Любой контейнер по умолчанию может попытаться получить доступ к host-системе
2. Если контейнер скомпрометирован и использует kernel exploit для выхода из контейнера, он получает root привилегии
3. Привилегия escalation возможна через Docker socket (любой, кто может подключиться к docker socket, может стать root)

Пример потенциальной уязвимости:

bash
<h2 id="konteyner-zapuschennyy-kak-root-v-docker-po-umolchaniyu">Контейнер, запущенный как root в Docker по умолчанию:</h2>
docker run -it ubuntu:22.04

<h2 id="vnutri-konteynera-rabotaet-kak-root">Внутри контейнера (работает как root):</h2>
id
<h2 id="uid-0-root-gid-0-root-groups-0-root">uid=0(root) gid=0(root) groups=0(root)</h2>

<h2 id="popytka-escape-iz-konteynera-mozhet-uspet">Попытка escape из контейнера может успеть</h2>
<h2 id="potomu-chto-konteyner-imeet-prava-root-na-host-sisteme">потому что контейнер имеет права root на хост-системе</h2>


Docker добавил rootless режим в версии 20.10, но это требует сложной настройки и часто сопровождается проблемами совместимости:

bash
<h2 id="vklyuchenie-rootless-docker-slozhnyy-protsess">Включение rootless Docker (сложный процесс)</h2>
sudo apt-get install docker-ce-rootless-extras uidmap
dockerd-rootless-setuptool.sh install


Даже после этой настройки многие инструменты не тестируются с rootless Docker, и могут возникать проблемы.

Podman и безопасность по умолчанию

Podman был разработан с учётом безопасности с самого начала. По умолчанию Podman работает в rootless режиме — вы можете запускать контейнеры как обычный пользователь:

bash
<h2 id="zapustit-konteyner-kak-obychnyy-polzovatel-bez-sudo">Запустить контейнер как обычный пользователь (без sudo)</h2>
podman run -d --name web nginx:latest

<h2 id="proverit-status">Проверить статус</h2>
podman ps

<h2 id="konteyner-rabotaet-no-kak-neprivilegirovannyy-protsess">Контейнер работает, но как непривилегированный процесс!</h2>
ps aux | grep nginx
<h2 id="pokazyvaet-protsess-ot-polzovatelya-user1-ne-ot-root">Показывает процесс от пользователя user1, не от root</h2>


При этом контейнер внутри видит себя как root (потому что это root внутри user namespace'а), но на хост-системе это обычный процесс пользователя с минимальными привилегиями.

Как работают user namespaces в Podman

Podman использует user namespace mapping для обеспечения безопасности:

bash
<h2 id="konfiguratsiya-v-etc-subuid-i-etc-subgid">Конфигурация в /etc/subuid и /etc/subgid</h2>
cat /etc/subuid
<h2 id="output-user1-100000-65536">Output: user1:100000:65536</h2>

<h2 id="eto-oznachaet-chto-uid-y-0-65535-vnutri-konteynera-user1">Это означает, что UID&#039;ы 0-65535 внутри контейнера user1</h2>
<h2 id="otobrazhayutsya-na-100000-165535-na-host-sisteme">отображаются на 100000-165535 на хост-системе</h2>

<h2 id="primer">Пример:</h2>
<h2 id="root-uid-0-vnutri-konteynera-user1-uid-100000-na-host-sisteme">root (uid=0) внутри контейнера user1 = uid=100000 на хост-системе</h2>
<h2 id="user-uid-1000-vnutri-konteynera-user1-uid-101000-na-host-sisteme">user (uid=1000) внутри контейнера user1 = uid=101000 на хост-системе</h2>


Это отображение предотвращает:
- Эскалацию привилегий через файловые права
- Доступ непривилегированного контейнера к файлам root'а на хост-системе
- Прямой доступ к device'ам на хост-системе

Сравнение моделей безопасности

АспектDockerPodman
Daemon привилегииrootN/A (нет daemon'а)
Контейнер привилегии (по умолчанию)root в системеroot в namespace (обычный пользователь на хост)
Доверие пользователямВсе в группе docker = эффективно rootКаждый пользователь изолирован
Rootless режимТребует сложной настройкиПо умолчанию
Привилегированный контейнер--privileged очень опасно--privileged менее опасно
Интеграция с SELinuxТребует конфигурацииВстроена
Compliance требованияСложнее выполнитьЛегче выполнить

Capabilities вместо --privileged

Вместо запуска контейнера с --privileged, используйте specific Linux capabilities:

bash
<h2 id="nepravilno-predostavlyaet-vse-vozmozhnye-prava">❌ Неправильно: предоставляет все возможные права</h2>
docker run --privileged ubuntu:22.04

<h2 id="pravilno-predostavlyaet-tolko-nuzhnye-rights">✅ Правильно: предоставляет только нужные rights</h2>
docker run --cap-add NET_ADMIN ubuntu:22.04 # Только для управления сетью
docker run --cap-add SYS_ADMIN ubuntu:22.04 # Только для системных операций

<h2 id="otpustit-opasnye-capabilities">Отпустить опасные capabilities</h2>
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE ubuntu:22.04


То же самое в Podman:

bash
podman run --cap-add NET_ADMIN ubuntu:22.04
podman run --cap-drop ALL --cap-add NET_BIND_SERVICE ubuntu:22.04


SELinux интеграция

Podman лучше интегрируется с SELinux (система обязательного контроля доступа Linux, используется в Red Hat based системах):

bash
<h2 id="podman-avtomaticheski-ispolzuet-selinux-konteksty">Podman автоматически использует SELinux контексты</h2>
podman run -it ubuntu:22.04
<h2 id="selinux-avtomaticheski-primenyaet-ogranicheniya-konteynera">SELinux автоматически применяет ограничения контейнера</h2>

<h2 id="docker-mozhet-trebovat-dopolnitelnoy-konfiguratsii">Docker может требовать дополнительной конфигурации</h2>
docker run --security-opt label=type:svirt_apache_t ubuntu:22.04


Аудит и Compliance

Для финансовых организаций и систем с compliance требованиями (HIPAA, PCI-DSS, GDPR, SOC 2) Podman часто предпочтительнее:

- Rootless режим отвечает принципам least privilege
- Лучшая изоляция между пользователями и контейнерами
- Лучшая интеграция с системным аудитом и логированием
- Подходит для OpenShift (часто требуется в enterprise окружениях)
- Может быть интегрирован с systemd journald для аудита

Многие финансовые институты требуют, чтобы каждое действие с контейнерами логировалось и было auditab'льно. Podman лучше это обеспечивает.



Производительность и потребление ресурсов


Вопрос производительности часто решающий для выбора инструмента. Давайте разберём реальные цифры, а не маркетинг.

Потребление памяти

Docker daemon всегда работает в фоне, даже когда вы не используете контейнеры:

bash
<h2 id="proverit-pamyat-daemon-ya">Проверить память daemon&#039;я</h2>
ps aux | grep dockerd
<h2 id="obychno-potreblyaet-50-150-mb-v-zavisimosti-ot-konfiguratsii-i-kolichestva-konteynerov">Обычно потребляет 50-150 MB в зависимости от конфигурации и количества контейнеров</h2>

<h2 id="podman-net-postoyannogo-protsessa">Podman: нет постоянного процесса</h2>
ps aux | grep podman
<h2 id="protsessy-podman-sozdayutsya-tolko-pri-aktivnyh-operatsiyah-zapusk-konteynera">Процессы Podman создаются только при активных операциях (запуск контейнера)</h2>
<h2 id="posle-ostanovki-konteynera-protsessy-zavershayutsya">После остановки контейнера процессы завершаются</h2>


На локальной машине разработчика с Ubuntu 22.04 и несколькими контейнерами:

Docker:
- Docker daemon: ~100 MB памяти
- Контейнеры: ~300 MB
- Итого: ~400 MB при неактивности

Podman:
- Контейнеры: ~300 MB
- Процессы Podman: ~0 MB (они завершены)
- Итого: ~300 MB при неактивности

На машине с 4 GB RAM и 100+ контейнерами:
- Docker daemon может потреблять 200-300 MB дополнительной памяти
- Podman не имеет этого overhead'а

Это может быть существенно на машинах с ограниченными ресурсами (ноутбуки, IoT устройства, shared hosting).

Скорость создания контейнеров

Тест на современной машине (Ubuntu 22.04, Intel i7-10700K, 16GB RAM):

bash
<h2 id="docker-sozdanie-100-konteynerov-posledovatelno">Docker: создание 100 контейнеров последовательно</h2>
time for i in {1..100}; do
docker run --rm alpine:latest echo "test" > /dev/null
done
<h2 id="primerno-25-30-sekund">Примерно: 25-30 секунд</h2>

<h2 id="podman-sozdanie-100-konteynerov-posledovatelno">Podman: создание 100 контейнеров последовательно</h2>
time for i in {1..100}; do
podman run --rm alpine:latest echo "test" > /dev/null
done
<h2 id="primerno-20-25-sekund">Примерно: 20-25 секунд</h2>


Podman немного быстрее (примерно на 10-15%), потому что не требует подключения к daemon'у через socket.

Скорость построения образов

bash
<h2 id="dockerfile-s-5-sloyami-razmer-100-mb">Dockerfile с 5 слоями, размер ~100 MB</h2>

<h2 id="docker-build-holodnyy-kesh">Docker build (холодный кеш)</h2>
time docker build -t test .
<h2 id="primerno-8-10-sekund">Примерно: 8-10 секунд</h2>

<h2 id="docker-build-goryachiy-kesh">Docker build (горячий кеш)</h2>
time docker build -t test .
<h2 id="primerno-0-5-sek">Примерно: 0.5 сек</h2>

<h2 id="podman-build-holodnyy-kesh">Podman build (холодный кеш)</h2>
time podman build -t test .
<h2 id="primerno-8-10-sekund">Примерно: 8-10 секунд</h2>

<h2 id="podman-build-goryachiy-kesh">Podman build (горячий кеш)</h2>
time podman build -t test .
<h2 id="primerno-0-5-sek">Примерно: 0.5 сек</h2>


Различие минимально.

Использование CPU при работающих контейнерах

Когда контейнеры активно работают, использование CPU практически идентично между Docker и Podman, потому что оба используют одинаковые Linux primitives (namespaces, cgroups).

bash
<h2 id="test-konteyner-s-vychisleniya-stress-test">Тест: контейнер с вычисления (stress-test)</h2>

<h2 id="docker">Docker</h2>
docker run --rm -it --cpus=1 --memory=512m stress-ng --cpu 1 --timeout 60s
<h2 id="cpu-95-100-ogranicheno-1-cpu-kak-ukazano">CPU: ~95-100% (ограничено 1 CPU как указано)</h2>
<h2 id="memory-512-mb-ogranicheno-kak-ukazano">Memory: ~512 MB (ограничено как указано)</h2>

<h2 id="podman">Podman</h2>
podman run --rm -it --cpus=1 --memory=512m stress-ng --cpu 1 --timeout 60s
<h2 id="cpu-95-100-odinakovo">CPU: ~95-100% (одинаково)</h2>
<h2 id="memory-512-mb-odinakovo">Memory: ~512 MB (одинаково)</h2>


Потребление CPU при построении больших образов

bash
<h2 id="dockerfile-s-50-sloyami-bolshaya-kompilyatsiya">Dockerfile с 50 слоями, большая компиляция</h2>

<h2 id="docker-build">Docker build</h2>
docker build --progress=plain -t test . 2>&1 | tail -5
<h2 id="cpu-15-20-vremya-45-60-sek">CPU: 15-20%, время: 45-60 сек</h2>

<h2 id="podman-build">Podman build</h2>
podman build --progress=plain -t test . 2>&1 | tail -5
<h2 id="cpu-15-20-odinakovo-vremya-45-60-sek-odinakovo">CPU: 15-20% (одинаково), время: 45-60 сек (одинаково)</h2>


Практически не различимо.

Производительность сети между контейнерами

Оба использует одинаковые механизмы (bridge networks, virtual ethernet devices, iptables rules).

bash
<h2 id="test-propusknoy-sposobnosti-s-iperf3">Тест пропускной способности с iperf3</h2>

<h2 id="docker">Docker</h2>
docker network create test-net
docker run -d --name server --network test-net iperf3:latest -s
docker run --rm --network test-net iperf3:latest -c server
<h2 id="primerno-5-10-gbps-zavisit-ot-host-mashiny">Примерно: 5-10 Gbps (зависит от хост-машины)</h2>

<h2 id="podman">Podman</h2>
podman network create test-net
podman run -d --name server --network test-net iperf3:latest -s
podman run --rm --network test-net iperf3:latest -c server
<h2 id="primerno-5-10-gbps-odinakovo">Примерно: 5-10 Gbps (одинаково)</h2>


Масштабируемость: сотни и тысячи контейнеров

На очень большой масштабе (500+ контейнеров):

- Docker daemon может стать bottleneck'ом при одновременных операциях (создание, удаление, запуск 100+ контейнеров одновременно)
- Podman лучше масштабируется, потому что нет центрального daemon'я, который должен обработать все запросы

Но в production для управления таким большим количеством контейнеров обычно используется Kubernetes, а не прямая работа с Docker/Podman CLI. Kubernetes распределяет контейнеры по нескольким машинам.

Практические выводы по производительности

Для большинства сценариев практической разработки и production развёртываний различие в производительности между Docker и Podman неощутимо (менее 5%).

Где Podman может иметь заметное преимущество:
- Локальная разработка (нет daemon'я в памяти, экономия ~100 MB на слабых ноутбуках)
- Очень большая масштабируемость (нет центрального bottleneck'а)
- IoT и edge устройства (экономия памяти)

Где Docker может иметь микроскопическое преимущество:
- Очень специфичные сценарии оптимизации (которые редко встречаются)

На практике выбор между Docker и Podman редко делается на основе производительности — это скорее архитектурный и стратегический выбор.



Работа с Pod: концепция и практическое применение


Pod — это концепция, которая отличает Podman от Docker. Хотя это может звучать как контейнер Docker, это совсем другое, и заимствовано из Kubernetes.

Что такое Pod в Podman

Pod (pod) в Podman — это группа контейнеров, которые работают вместе и совместно используют некоторые ресурсы на хост-системе.

Контейнеры в одном Pod совместно используют:
- Network namespace (один IP адрес, коммуникация между контейнерами через localhost)
- IPC namespace (коммуникация через shared memory, POSIX очереди, семафоры)
- UTS namespace (одно имя хоста для всех контейнеров)
- Могут совместно использовать volumes

Практический пример Pod'я:

pod
: "web-application"
├── Контейнер 1: nginx (порт 8080)
│ └── Роль: reverse proxy и статические файлы
├── Контейнер 2: backend-app (порт 8000)
│ └── Роль: основное приложение
├── Контейнер 3: log-collector (нет портов)
│ └── Роль: собирает логи от nginx и app
└── Монтирование volume'ов:
├── shared-logs: /var/log (для логов)
└── config: /etc/config (для конфигурации)


Все три контейнера видят друг друга как localhost:

bash
<h2 id="vnutri-konteynera-nginx">Внутри контейнера nginx</h2>
curl http://localhost:8000 # Доступен backend-app на том же порту

<h2 id="vnutri-konteynera-backend-app">Внутри контейнера backend-app</h2>
curl http://localhost # Доступен nginx


Создание и управление Pod'ами в Podman

bash
<h2 id="sozdat-pod-s-imenem-i-portami">Создать pod с именем и портами</h2>
podman pod create --name myapp -p 8080:80 -p 8000:8000

<h2 id="zapustit-konteyner-v-pod">Запустить контейнер в pod</h2>
podman run -d --pod myapp --name nginx nginx:latest

<h2 id="zapustit-vtoroy-konteyner-v-tom-zhe-pod">Запустить второй контейнер в том же pod</h2>
podman run -d --pod myapp --name app python:3.11 python app.py

<h2 id="zapustit-log-collector">Запустить log collector</h2>
podman run -d --pod myapp --name logger busybox:latest tail -f /var/log/app.log

<h2 id="spisok-pod-ov">Список pod&#039;ов</h2>
podman pod ls

<h2 id="podrobnaya-informatsiya-o-pod-e">Подробная информация о pod&#039;е</h2>
podman pod inspect myapp

<h2 id="poluchit-logi-vseh-konteynerov-v-pod">Получить логи всех контейнеров в pod</h2>
podman pod logs myapp

<h2 id="ostanovit-pod-ostanovit-vse-konteynery-v-pod-e">Остановить pod (остановит все контейнеры в pod&#039;е)</h2>
podman pod stop myapp

<h2 id="zapustit-pod">Запустить pod</h2>
podman pod start myapp

<h2 id="perezagruzit-pod">Перезагрузить pod</h2>
podman pod restart myapp

<h2 id="udalit-pod-udalit-vse-konteynery-i-infra-konteyner">Удалить pod (удалит все контейнеры и инфра контейнер)</h2>
podman pod rm myapp


Внутренняя коммуникация в Pod

Контейнеры в pod видят друг друга через localhost:

bash
<h2 id="na-host-sisteme-raznye-port-y-dlya-raznyh-konteynerov">На хост-системе (разные port&#039;ы для разных контейнеров)</h2>
podman pod create --name myapp -p 8080:80 -p 8000:8000

<h2 id="zapustit-nginx-na-portu-80">Запустить nginx на порту 80</h2>
podman run -d --pod myapp -p 80:80 nginx:latest

<h2 id="zapustit-app-na-portu-8000">Запустить app на порту 8000</h2>
podman run -d --pod myapp -p 8000:8000 python:3.11 python -m http.server 8000

<h2 id="vnutri-konteynera-nginx">Внутри контейнера nginx:</h2>
podman exec -it myapp-nginx /bin/bash
curl http://localhost:8000 # Доступен app!

<h2 id="na-host-sisteme">На хост-системе:</h2>
curl http://localhost:8080 # Доступен nginx
curl http://localhost:8000 # Доступен app


Pod vs Docker Compose

Docker не имеет встроенной концепции Pod'ов. Docker Compose достигает похожей функциональности через сеть, но контейнеры не совместно используют namespaces:

yaml
<h2 id="docker-compose-yml">docker-compose.yml</h2>
services:
nginx:
image: nginx:latest
ports:
- "8080:80"
depends_on:
- app

app:
image: python:3.11
ports:
- "8000:8000"
command: python -m http.server 8000

logger:
image: busybox:latest
command: tail -f /var/log/app.log


В Docker Compose контейнеры подключены к одной сети, но у каждого свой IP адрес. Они видят друг друга как `service-name:port`, а не как localhost.

Сравнение:

АспектDocker ComposePodman Pod
Network sharingРазные IP в одной сетиОдин IP (локальный)
Как видят друг другаПо имени сервиса (app:8000)Через localhost (localhost:8000)
Удобство использованияПростой YAML синтаксисНемного сложнее (командная строка)
PerformanceХорошоНемного лучше (меньше оверхеда)
Kubernetes compatibilityНе совместим напрямуюСовместим с K8S Pod'ами

Экспорт Pod как systemd сервиса

Мощная функция Podman (которая отсутствует в Docker) — генерация systemd unit файлов:

bash
<h2 id="sozdat-pod-s-konteynerami">Создать pod с контейнерами</h2>
podman pod create --name myapp
podman run -d --pod myapp --name web nginx:latest
podman run -d --pod myapp --name app python:3.11

<h2 id="eksportirovat-pod-kak-systemd-unit-fayl">Экспортировать pod как systemd unit файл</h2>
podman generate systemd --new myapp > /etc/systemd/user/myapp.service

<h2 id="vklyuchit-v-avtozagruzku">Включить в автозагрузку</h2>
systemctl --user daemon-reload
systemctl --user enable myapp.service

<h2 id="zapustit-pod-kak-systemd-servis">Запустить pod как systemd сервис</h2>
systemctl --user start myapp.service

<h2 id="proverit-status">Проверить статус</h2>
systemctl --user status myapp.service

<h2 id="prosmotr-logov">Просмотр логов</h2>
journalctl --user -u myapp.service -f


Pod теперь полностью управляется systemd как обычный Linux сервис! Это означает:
- Pod автоматически стартует при загрузке системы
- Pod автоматически перезагружается если crashed
- Логи интегрированы в systemd journald
- Можно управлять как `systemctl start myapp`

Pod в Kubernetes

Концепция Pod в Podman полностью заимствована из Kubernetes. Pod в Kubernetes имеет ту же семантику: группа контейнеров, совместно использующих network namespace.

Kubernetes Pod YAML:

yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: nginx
image: nginx:latest
- name: app
image: python:3.11
command: ["python", "-m", "http.server", "8000"]
- name: logger
image: busybox:latest
command: ["tail", "-f", "/var/log/app.log"]


Это же определение можно запустить локально в Podman:

bash
<h2 id="sohranyaet-v-fayl-pod-yaml">Сохраняет в файл pod.yaml</h2>
podman play kube pod.yaml
<h2 id="pod-zapuskaetsya-v-podman-s-temi-zhe-konteynerami">Pod запускается в Podman с теми же контейнерами</h2>

<h2 id="pozzhe-ostanovit-pod">Позже, остановить pod</h2>
podman play kube --down pod.yaml


Это позволяет разработчикам тестировать Kubernetes Pod'ы локально перед развёртыванием в настоящем Kubernetes кластере!



Docker Compose vs Podman Compose


Compose файлы практически идентичны между Docker и Podman. Различия минимальны, что делает миграцию простой.

Установка

bash
<h2 id="docker-compose-obychno-vklyuchen-v-docker-desktop-dlya-macos-i-windows">Docker Compose (обычно включен в Docker Desktop для macOS и Windows)</h2>
<h2 id="na-linux-mozhet-potrebovatsya-ustanovit-otdelno">На Linux может потребоваться установить отдельно:</h2>
sudo apt install docker-compose-plugin
<h2 id="ili">или</h2>
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

<h2 id="podman-compose">Podman Compose</h2>
sudo apt install podman-compose
<h2 id="ili-cherez-pip">или через pip</h2>
pip3 install podman-compose


Полный Compose файл (работает с обоими)

yaml
version: '3.8'

services:
web:
image: nginx:latest
container_name: web-server
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- frontend
environment:
- NGINX_HOSTNAME=example.com
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3

api:
build:
context: ./api
dockerfile: Dockerfile
args:
VERSION: 1.0
image: myapi:1.0
container_name: api-server
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://db:5432/mydb
- REDIS_URL=redis://cache:6379
- NODE_ENV=production
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks:
- frontend
- backend
volumes:
- ./api/src:/app/src
- api_logs:/app/logs
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"

db:
image: postgres:15-alpine
container_name: postgres-db
environment:
- POSTGRES_DB=mydb
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=securepassword
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin"]
interval: 10s
timeout: 5s
retries: 5

cache:
image: redis:7-alpine
container_name: redis-cache
ports:
- "6379:6379"
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped

volumes:
postgres_data:
driver: local
redis_data:
driver: local
api_logs:
driver: local

networks:
frontend:
driver: bridge
backend:
driver: bridge


Команды (полностью идентичны)

bash
<h2 id="zapustit-vse-servisy">Запустить все сервисы</h2>
docker-compose up -d
podman-compose up -d

<h2 id="prosmotr-logov-vseh-servisov">Просмотр логов всех сервисов</h2>
docker-compose logs -f
podman-compose logs -f

<h2 id="logi-konkretnogo-servisa">Логи конкретного сервиса</h2>
docker-compose logs -f api
podman-compose logs -f api

<h2 id="spisok-servisov-i-ih-status">Список сервисов и их статус</h2>
docker-compose ps
podman-compose ps

<h2 id="ostanovit-vse-servisy">Остановить все сервисы</h2>
docker-compose down
podman-compose down

<h2 id="ostanovit-i-udalit-volumes">Остановить и удалить volumes</h2>
docker-compose down -v
podman-compose down -v

<h2 id="ostanovit-servis">Остановить сервис</h2>
docker-compose stop api
podman-compose stop api

<h2 id="startovat-servis">Стартовать сервис</h2>
docker-compose start api
podman-compose start api

<h2 id="perezagruzit-servis">Перезагрузить сервис</h2>
docker-compose restart api
podman-compose restart api

<h2 id="perestroit-obraz">Перестроить образ</h2>
docker-compose build api
podman-compose build api

<h2 id="vypolnit-komandu-v-servise">Выполнить команду в сервисе</h2>
docker-compose exec api npm test
podman-compose exec api npm test

<h2 id="masshtabirovat-servis-esli-vozmozhno">Масштабировать сервис (если возможно)</h2>
docker-compose up -d --scale api=3
podman-compose up -d --scale api=3

<h2 id="udalit-servis">Удалить сервис</h2>
docker-compose rm api
podman-compose rm api

<h2 id="vyvesti-configuration-obedinyonnyy">Вывести configuration (объединённый)</h2>
docker-compose config
podman-compose config


Различия в поведении

1. Networking: Оба создают bridge сеть и подключают сервисы. DNS resolution работает одинаково.

2. Volumes: Docker и Podman создают отдельные volume'ы — несовместимы между собой. Volume созданный docker-compose не видна в podman-compose и наоборот.

3. Контейнер naming: Оба используют похожую схему: `projectname_servicename_1`, но может различаться по деталям.

4. Build context: Оба поддерживают `build` с directory и Dockerfile.

5. Environment variables: .env файлы поддерживаются обоими.

6. Зависимости: `depends_on` работает в обоих и может использовать `condition: service_healthy`.

Миграция docker-compose.yml на podman-compose

В 99% случаев достаточно просто заменить команду:

bash
<h2 id="bylo">Было</h2>
docker-compose up -d

<h2 id="stalo">Стало</h2>
podman-compose up -d


Процесс миграции:

bash
<h2 id="shag-1-skachat-vse-obrazy">Шаг 1: Скачать все образы</h2>
podman-compose pull

<h2 id="shag-2-zapustit-servisy">Шаг 2: Запустить сервисы</h2>
podman-compose up -d

<h2 id="shag-3-proverit-logi">Шаг 3: Проверить логи</h2>
podman-compose logs -f

<h2 id="shag-4-protestirovat-funktsionalnost-prilozheniya">Шаг 4: Протестировать функциональность приложения</h2>

<h2 id="shag-5-esli-vsyo-rabotaet-zamenit-vezde-gde-nuzhno">Шаг 5: Если всё работает, заменить везде где нужно</h2>
<h2 id="ci-cd-skripty">- CI/CD скрипты</h2>
<h2 id="dokumentatsiya">- Документация</h2>
<h2 id="readme-fayly">- README файлы</h2>
<h2 id="skripty-avtomatizatsii">- Скрипты автоматизации</h2>


Особые случаи при миграции

1. Volume paths: Если использовались абсолютные пути, убедиться что они доступны в Podman:

yaml
<h2 id="mozhet-byt-problema-v-rootless-podman">❌ Может быть проблема в rootless Podman</h2>
volumes:
- /root-owned-path:/app/data

<h2 id="luchshe-ispolzovat-named-volumes">✅ Лучше использовать named volumes</h2>
volumes:
my-volume:
driver: local


2. Docker-in-Docker (DinD): Если используется DinD, это может не работать в Podman. Решение: использовать Podman-in-Podman:

yaml
<h2 id="bylo-docker">Было (Docker)</h2>
dind:
image: docker:latest
privileged: true

<h2 id="stalo-podman">Стало (Podman)</h2>
podman-in-podman:
image: podman:latest
privileged: true


3. Custom networks с IP address assignment:

yaml
services:
app:
image: myapp:latest
networks:
mynet:
ipv4_address: 172.20.0.2


Это работает в обоих, но убедиться в совместимости IP range'а с существующими сетями.



Networking: сети, DNS и коммуникация


Networking — критический аспект работы с контейнерами. Docker и Podman имеют похожий подход, но есть нюансы.

Типы сетей в обоих инструментах

И Docker, и Podman поддерживают несколько типов сетей:

1. Bridge сеть (по умолчанию) — виртуальная bridge сеть, контейнеры получают IP адреса
2. Host сеть — контейнер использует сетевой стек хост-системы напрямую
3. None сеть — контейнер без сетевого подключения (только loopback интерфейс)
4. Custom user-defined сеть — сеть с кастомными параметрами, определённая пользователем

Bridge сеть и автоматический DNS

bash
<h2 id="sozdat-polzovatelskuyu-bridge-set">Создать пользовательскую bridge сеть</h2>
docker network create mynet
podman network create mynet

<h2 id="zapustit-konteynery-v-seti">Запустить контейнеры в сети</h2>
docker run -d --network mynet --name database postgres:15
docker run -it --network mynet --name app ubuntu:22.04

<h2 id="vnutri-konteynera-app">Внутри контейнера app:</h2>
ping database
<h2 id="output-ping-database-172-18-0-2-56-84-bytes-of-data">Output: PING database (172.18.0.2) 56(84) bytes of data.</h2>
<h2 id="rabotaet-dns-avtomaticheski-razreshil-imya-database">Работает! DNS автоматически разрешил имя database</h2>

<h2 id="eto-rabotaet-potomu-chto-obe-platformy-imeyut-vstroennyy-dns-server">Это работает потому что обе платформы имеют встроенный DNS сервер</h2>
<h2 id="kotoryy-razreshaet-imena-konteynerov-v-seti">который разрешает имена контейнеров в сети</h2>


То же самое в Podman:

bash
podman network create mynet
podman run -d --network mynet --name database postgres:15
podman run -it --network mynet --name app ubuntu:22.04

<h2 id="vnutri-konteynera-app">Внутри контейнера app:</h2>
ping database # Работает одинаково


Host сеть (для производительности)

Host сеть означает, что контейнер использует сетевой стек хост-системы напрямую, без виртуализации:

bash
<h2 id="docker">Docker</h2>
docker run -it --network host ubuntu:22.04
ip addr # Вы увидите реальные сетевые интерфейсы хост-системы

<h2 id="podman">Podman</h2>
podman run -it --network host ubuntu:22.04
ip addr # Аналогично


Host сеть используется для performance-critical приложений, которым нужна низкая latency (например, high-frequency trading системы).

Port binding и публикация портов

bash
<h2 id="privyazat-port-publish-port">Привязать порт (publish port)</h2>
docker run -d -p 8080:80 nginx:latest
podman run -d -p 8080:80 nginx:latest
<h2 id="na-localhost-8080-teper-dostupen-nginx-v-konteynere-na-portu-80">На localhost:8080 теперь доступен nginx в контейнере на порту 80</h2>

<h2 id="privyazat-k-konkretnomu-interfeysu">Привязать к конкретному интерфейсу</h2>
docker run -d -p 127.0.0.1:8080:80 nginx:latest # Только localhost
docker run -d -p 192.168.1.100:8080:80 nginx:latest # Конкретный интерфейс

<h2 id="random-port-na-host-sisteme">Random порт на хост-системе</h2>
docker run -d -p :80 nginx:latest # Случайный порт (например 32768) на localhost:80

<h2 id="proverit-kakoy-port-ispolzovan">Проверить какой порт использован</h2>
docker ps
<h2 id="ports-0-0-0-0-32768-80-tcp">PORTS: 0.0.0.0:32768-&gt;80/tcp</h2>

<h2 id="neskolko-portov">Несколько портов</h2>
docker run -d -p 8080:80 -p 8443:443 nginx:latest


Custom networks для микросервисов

bash
<h2 id="prakticheskiy-primer-mikroservisnaya-arhitektura">Практический пример: микросервисная архитектура</h2>

<h2 id="sozdat-seti">Создать сети</h2>
docker network create frontend
docker network create backend

<h2 id="servis-1-api-gateway">Сервис 1: API Gateway</h2>
docker run -d --network frontend --name api-gateway -p 8000:8000 \
-e BACKEND_URL=http://api-service:3000 \
mygateway:latest

<h2 id="servis-2-backend-api">Сервис 2: Backend API</h2>
docker run -d --network backend --name api-service \
-e DB_HOST=postgres \
-e CACHE_HOST=redis \
myapi:latest

<h2 id="servis-3-bd">Сервис 3: БД</h2>
docker run -d --network backend --name postgres \
-e POSTGRES_PASSWORD=secret \
postgres:15

<h2 id="servis-4-redis-kesh">Сервис 4: Redis кеш</h2>
docker run -d --network backend --name redis redis:7

<h2 id="api-gateway-podklyuchit-k-obeim-setyam">API Gateway подключить к обеим сетям</h2>
docker network connect backend api-gateway

<h2 id="teper">Теперь:</h2>
<h2 id="api-gateway-vidit-api-service-postgres-redis-po-imeni-localhost-set">- API Gateway видит api-service, postgres, redis по имени (localhost сеть)</h2>
<h2 id="api-service-vidit-postgres-i-redis-backend-set">- api-service видит postgres и redis (backend сеть)</h2>
<h2 id="vneshniy-klient-podklyuchaetsya-k-localhost-8000-api-gateway">- Внешний клиент подключается к localhost:8000 (api-gateway)</h2>


Networking в docker-compose / podman-compose

Compose автоматически создаёт сеть и подключает сервисы:

yaml
version: '3.8'

services:
api:
image: myapi:latest
networks:
- backend
environment:
- DB_HOST=postgres # Автоматически разрешит в DNS
- CACHE_HOST=redis

postgres:
image: postgres:15
networks:
- backend

redis:
image: redis:7
networks:
- backend

nginx:
image: nginx:latest
networks:
- frontend
ports:
- "80:80"
depends_on:
- api

networks:
frontend:
driver: bridge
backend:
driver: bridge


Compose автоматически:
1. Создаст сети frontend и backend
2. Подключит сервисы к нужным сетям
3. Создаст DNS записи для разрешения имён (api → api:3000 и т.д.)
4. Управляет порт-публикацией

Firewall и iptables

И Docker, и Podman используют iptables для управления трафиком между контейнерами и хост-системой.

После выполнения `docker run -d -p 8080:80 nginx` Docker добавляет правила в iptables:

bash
<h2 id="proverit-pravila">Проверить правила</h2>
sudo iptables -L -n | grep 8080

<h2 id="output-primerno">Output примерно:</h2>
<h2 id="dnat-tcp-0-0-0-0-0-0-0-0-0-0-tcp-dpt-8080-to-172-17-0-2-80">DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80</h2>


Это правило говорит: весь трафик на порт 8080 переводить на контейнер (IP 172.17.0.2) на порт 80.

⚠️ Осторожно с изменением iptables вручную — может сломать networking контейнеров.

DNS разрешение контейнерами

Контейнеры используют встроенный DNS сервер платформы:

bash
<h2 id="proverit-dns-server-v-konteynere">Проверить DNS сервер в контейнере</h2>
docker run -it ubuntu:22.04 cat /etc/resolv.conf

<h2 id="docker-output">Docker output:</h2>
<h2 id="nameserver-127-0-0-11">nameserver 127.0.0.11</h2>
<h2 id="options-edns0-ndots-0">options edns0 ndots:0</h2>

<h2 id="podman-output-mozhet-otlichatsya-ispolzuet-systemd-resolved">Podman output может отличаться (использует systemd-resolved)</h2>




Volumes и управление данными контейнеров


Volumes — механизм для хранения persistent данных в контейнерах. Docker и Podman имеют похожий подход, но с нюансами в rootless режиме Podman.

Named volumes (рекомендуется)

Named volumes — это предпочтительный способ хранения данных. Платформа управляет их расположением на хост-системе.

bash
<h2 id="sozdat-volume">Создать volume</h2>
docker volume create pgdata
podman volume create pgdata

<h2 id="ispolzovat-volume-v-konteynere">Использовать volume в контейнере</h2>
docker run -d -v pgdata:/var/lib/postgresql/data postgres:15
podman run -d -v pgdata:/var/lib/postgresql/data postgres:15

<h2 id="spisok-volumes">Список volumes</h2>
docker volume ls
podman volume ls

<h2 id="detalnaya-informatsiya-o-volume">Детальная информация о volume</h2>
docker volume inspect pgdata
podman volume inspect pgdata

<h2 id="output-dlya-docker">Output для Docker:</h2>
<h2 id="mountpoint-var-lib-docker-volumes-pgdata-data">&quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/pgdata/_data&quot;</h2>

<h2 id="output-dlya-podman">Output для Podman:</h2>
<h2 id="mountpoint-var-lib-containers-storage-volumes-pgdata-data">&quot;Mountpoint&quot;: &quot;/var/lib/containers/storage/volumes/pgdata/_data&quot;</h2>

<h2 id="udalit-volume-udalyaet-dannye">Удалить volume (⚠️ удаляет данные)</h2>
docker volume rm pgdata
podman volume rm pgdata

<h2 id="udalit-volume-pri-udalenii-konteynera">Удалить volume при удалении контейнера</h2>
docker run --rm -v pgdata:/data ubuntu:22.04


Bind mounts (монтирование директорий хост-системы)

Bind mount монтирует директорию хост-системы в контейнер:

bash
<h2 id="prostoy-bind-mount">Простой bind mount</h2>
docker run -d -v /host/path:/container/path postgres:15
podman run -d -v /host/path:/container/path postgres:15

<h2 id="montirovat-tekuschuyu-direktoriyu-dlya-razrabotki">Монтировать текущую директорию (для разработки)</h2>
docker run -it -v $(pwd):/app ubuntu:22.04
podman run -it -v $(pwd):/app ubuntu:22.04

<h2 id="read-only-mount">Read-only mount</h2>
docker run -d -v /host/path:/container/path:ro postgres:15

<h2 id="s-optsiyami-zavisit-ot-file-system">С опциями (зависит от file system)</h2>
docker run -d -v /host/path:/container/path:rshared,rslave postgres:15


Bind mounts часто используются для разработки (код на хост-системе, контейнер выполняет код).

Права доступа к volumes (важно в rootless Podman)

При использовании bind mounts в rootless Podman могут быть проблемы с правами доступа:

bash
<h2 id="fayl-prinadlezhit-root-na-host-sisteme">Файл принадлежит root на хост-системе</h2>
ls -la /root-owned-file
<h2 id="rw-r-r-1-root-root-1000-may-8-12-00">-rw-r--r-- 1 root root 1000 May 8 12:00</h2>

<h2 id="docker-daemon-rabotaet-kak-root-poetomu-mozhet-skopirovat">Docker daemon работает как root, поэтому может скопировать</h2>
docker run -v /root-owned-file:/data ubuntu:22.04

<h2 id="podman-v-rootless-rezhime-mozhet-ne-poluchit-dostup">Podman в rootless режиме может не получить доступ</h2>
podman run -v /root-owned-file:/data ubuntu:22.04
<h2 id="mozhet-poluchit-permission-denied">Может получить Permission denied</h2>

<h2 id="reshenie-1-ispolzovat-named-volumes">Решение 1: использовать named volumes</h2>
podman volume create mydata
podman run -v mydata:/data ubuntu:22.04 # Работает

<h2 id="reshenie-2-izmenit-prava-dostupa-na-fayl">Решение 2: изменить права доступа на файл</h2>
sudo chmod 644 /root-owned-file

<h2 id="reshenie-3-smontirovat-s-optsiyami-mozhet-ne-rabotat">Решение 3: смонтировать с опциями (может не работать)</h2>
podman run -v /root-owned-file:/data:U ubuntu:22.04 # U = chown to user


Backup и restore volumes

Для важных данных нужен регулярный backup:

bash
<h2 id="backup-volume-v-tar-arhiv">Backup volume в tar архив</h2>
docker run --rm -v pgdata:/data -v $(pwd):/backup \
ubuntu:22.04 tar czf /backup/pgdata.tar.gz /data

<h2 id="restore-volume-iz-tar-arhiva">Restore volume из tar архива</h2>
podman volume create pgdata
podman run --rm -v pgdata:/data -v $(pwd):/backup \
ubuntu:22.04 tar xzf /backup/pgdata.tar.gz -C /

<h2 id="proverit-dannye-vosstanovleny">Проверить данные восстановлены</h2>
podman run --rm -v pgdata:/data ubuntu:22.04 ls /data


Volumes в docker-compose / podman-compose

yaml
version: '3.8'

services:
postgres:
image: postgres:15
volumes:
# Named volume
- postgres_data:/var/lib/postgresql/data
# Bind mount (для разработки)
- ./init-scripts:/docker-entrypoint-initdb.d:ro
# Backup директория
- /backup:/backup:ro

app:
image: myapp:latest
volumes:
# Named volume для app данных
- app_data:/app/data
# Bind mount для разработки (код)
- ./src:/app/src
# Лог директория
- ./logs:/app/logs

<h2 id="opredelit-named-volumes">Определить named volumes</h2>
volumes:
postgres_data:
driver: local
app_data:
driver: local


Очистка неиспользуемых volumes

bash
<h2 id="spisok-volumes">Список volumes</h2>
docker volume ls

<h2 id="udalit-volume">Удалить volume</h2>
docker volume rm volume_name

<h2 id="udalit-vse-neispolzuemye-volumes-ostorozhno">Удалить все неиспользуемые volumes (осторожно!)</h2>
docker volume prune
podman volume prune

<h2 id="udalit-volume-s-konteynerom">Удалить volume с контейнером</h2>
docker rm -v container_name # -v удалит связанные volumes




Оркестрация с Kubernetes и OpenShift


Kubernetes стал стандартом для оркестрации контейнеров. Docker и Podman оба работают с Kubernetes, но по-разному.

Docker в Kubernetes

Docker контейнеры работают в Kubernetes через Container Runtime Interface (CRI). В старых версиях Kubernetes (до 1.20) Docker был встроенным runtime. Сейчас Kubernetes использует containerd (который был частью Docker) или CRI-O (который полностью совместим с Podman).

bash
<h2 id="kubernetes-pod-yaml-rabotaet-s-lyubym-runtime">Kubernetes Pod YAML (работает с любым runtime)</h2>
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: my-app
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
limits:
memory: "256Mi"
cpu: "500m"
- name: app
image: myapp:latest
ports:
- containerPort: 8000
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
EOF


Podman и локальная разработка Kubernetes

Podman поддерживает Kubernetes Play (запуск Kubernetes YAML локально):

bash
<h2 id="zapustit-kubernetes-pod-s-podman-lokalno">Запустить Kubernetes Pod с Podman локально</h2>
podman play kube my-pod.yaml

<h2 id="eto-udobno-dlya-lokalnoy-razrabotki-i-testirovaniya-pered-razvyortyvaniem-v-nastoyaschiy-k8s">Это удобно для локальной разработки и тестирования перед развёртыванием в настоящий K8S</h2>


Подготовка образов для Kubernetes

В обоих случаях образы должны быть в registry (Docker Hub, AWS ECR, Google Artifact Registry и т.д.):

bash
<h2 id="postroit-obraz">Построить образ</h2>
docker build -t myapp:1.0 .
podman build -t myapp:1.0 .

<h2 id="otpravit-v-registry">Отправить в registry</h2>
docker tag myapp:1.0 registry.company.com/myapp:1.0
docker push registry.company.com/myapp:1.0

podman tag myapp:1.0 registry.company.com/myapp:1.0
podman push registry.company.com/myapp:1.0

<h2 id="v-kubernetes-yaml">В Kubernetes YAML</h2>
image: registry.company.com/myapp:1.0
imagePullPolicy: Always


Локальная разработка Kubernetes приложений

Используйте minikube или kind для локального Kubernetes кластера:

bash
<h2 id="ustanovit-minikube">Установить minikube</h2>
curl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

<h2 id="zapustit-kubernetes-s-podman-vmesto-docker">Запустить Kubernetes с Podman (вместо Docker)</h2>
minikube start --driver=podman

<h2 id="proverit-chto-klaster-rabotaet">Проверить что кластер работает</h2>
kubectl cluster-info
kubectl get nodes

<h2 id="teper-mozhno-razvyortyvat-prilozheniya">Теперь можно развёртывать приложения</h2>
kubectl create deployment myapp --image=myapp:1.0
kubectl expose deployment myapp --type=LoadBalancer --port=8080


OpenShift и Podman

OpenShift — коммерческая Kubernetes платформа от Red Hat, использует Podman (и CRI-O runtime).

bash
<h2 id="esli-vy-ispolzuete-openshift-vy-ispolzuete-podman-instrumenty">Если вы используете OpenShift, вы используете Podman инструменты</h2>
oc login https://openshift.company.com:6443

<h2 id="sozdat-proekt">Создать проект</h2>
oc new-project myapp

<h2 id="razvernut-prilozhenie">Развернуть приложение</h2>
oc apply -f deployment.yaml

<h2 id="prosmotr-pod-ov">Просмотр Pod&#039;ов</h2>
oc get pods

<h2 id="prosmotr-logov">Просмотр логов</h2>
oc logs pod-name

<h2 id="portforvarding">Портфорвардинг</h2>
oc port-forward pod-name 8080:8080


OpenShift часто используется в финансовом и государственном секторе из-за лучшей безопасности (использует Podman rootless по умолчанию).

Buildpacks и создание образов в Kubernetes

Для создания образов внутри Kubernetes (CI/CD) используется BuildKit (встроен в Docker) или Buildah (для Podman):

bash
<h2 id="docker-s-buildkit-bolee-bystroe-postroenie">Docker с BuildKit (более быстрое построение)</h2>
DOCKER_BUILDKIT=1 docker build -t myapp:1.0 .

<h2 id="podman-buildkit-vstroen-po-umolchaniyu">Podman (BuildKit встроен по умолчанию)</h2>
podman build -t myapp:1.0 .

<h2 id="ili-ispolzovat-buildah-napryamuyu">Или использовать Buildah напрямую</h2>
buildah bud -t myapp:1.0 .

<h2 id="buildah-mozhet-byt-bystree-dlya-bolshie-dockerfile-ov">Buildah может быть быстрее для большие Dockerfile&#039;ов</h2>




Практические сценарии: когда выбрать Docker, когда Podman


Давайте разберём конкретные сценарии и какой инструмент лучше для каждого.

Сценарий 1: Стартап, разработка нового проекта с нуля

У вас есть полная свобода выбора инструментов, и вы начинаете новый проект.

Рекомендация: Podman

Почему:
- Экономия ресурсов на локальной разработке (особенно важно для ноутбуков)
- Rootless режим безопаснее для разработки
- Бесплатен (Podman), нет нужды в Docker Desktop лицензии
- Готов к Kubernetes из коробки
- Лучше интегрируется с systemd (стандарт Linux)

Как внедрить:
- Локальная разработка: podman-compose
- CI/CD: GitHub Actions с podman
- Production: Kubernetes с Podman runtime

Сценарий 2: Legacy система на Docker, работает 5+ лет

У вас есть система на Docker, полностью настроенная, сотни контейнеров, инвестиции в экосистему.

Рекомендация: Оставить Docker (если нет критических причин)

Почему:
- Миграция требует времени (недели/месяцы) и ресурсов
- Система работает стабильно, finansially окупилась
- Команда обучена Docker, затраты на переучивание
- Риск регрессии и потери стабильности при миграции

Когда рассмотреть миграцию:
- Появились критические уязвимости в Docker daemon
- Требования безопасности ужесточились (compliance, регуляторные требования)
- Нужна интеграция с OpenShift (Red Hat платформа для enterprise)
- Лицензирование Docker стало экономически невыгодно

Сценарий 3: Multi-user CI/CD система, Jenkins/GitLab Runner

У вас есть система, где разные пользователи (разработчики, CI/CD) запускают контейнеры на одной машине.

Рекомендация: Podman

Почему:
- Безопасность между пользователями (user namespace isolation)
- Каждый пользователь может запускать контейнеры независимо
- Не требуется добавлять пользователей в группу docker (что имеет последствия для безопасности)
- Rootless режим предотвращает эскалацию привилегий

Практическая конфигурация для Jenkins:

groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'podman build -t myregistry.com/myapp:${BUILD_NUMBER} .'
sh 'podman run --rm myregistry.com/myapp:${BUILD_NUMBER} npm test'
}
}
stage('Push') {
steps {
sh 'podman push myregistry.com/myapp:${BUILD_NUMBER}'
}
}
}
}


Jenkins работает под пользователем jenkins, контейнеры запускаются безопасно в rootless режиме.

Сценарий 4: Облачное развёртывание, AWS ECS / Google Cloud Run

Вы хостите контейнеры в управляемых облачных сервисах.

Рекомендация: Docker (инструменты в облаке используют Docker)

Почему:
- AWS ECS оптимизирован для Docker
- Docker образы — де-факто стандарт в облачных платформах
- Интеграция с AWS ECR и Google Container Registry лучше
- Меньше проблем совместимости

Однако:
- Вы по-прежнему можете использовать Podman локально для разработки
- Docker образы совместимы между Docker и Podman
- CI/CD может использовать Podman, результат публикуется как Docker образ

Рекомендуемый процесс:
1. Разрабатывать локально с Podman (быстрее, меньше памяти)
2. CI/CD строит образ с Podman
3. Публикует образ в AWS ECR как Docker образ
4. AWS ECS запускает контейнеры

Сценарий 5: High-security окружение, финансовая компания

Вы работаете в банке или финансовой компании с высокими требованиями безопасности и compliance.

Рекомендация: Podman

Почему:
- Rootless по умолчанию соответствует принципам least privilege
- User namespace isolation предотвращает компрометацию одного контейнера влияния на другие
- Нет daemon'я (меньше поверхность атаки)
- Лучше для аудита и compliance требований (NIST, PCI-DSS, GDPR, SOC 2)
- Часто требуется в enterprise окружениях

Интеграция с compliance:
- Systemd integration для логирования и аудита
- SELinux поддержка для обязательного контроля доступа
- Возможность интеграции с OpenShift (требуется многими банками)

Сценарий 6: IoT и edge computing

Вы развёртываете контейнеры на IoT устройствах (Raspberry Pi, industrial controllers) с ограниченными ресурсами.

Рекомендация: Podman

Почему:
- Потребляет меньше памяти (нет постоянного daemon'я)
- Более эффективно использует CPU
- Rootless режим подходит для IoT
- Меньше зависимостей

Практическое сравнение на Raspberry Pi 4 (4GB RAM):
- Docker daemon + простой контейнер: ~200-300 MB памяти
- Podman контейнер: ~50-100 MB памяти

Это значимо для IoT, где каждый MB памяти дорог.

Сценарий 7: Разработка микросервисов локально

Вы разрабатываете микросервисное приложение с 10-20 сервисами, тестируете локально на ноутбуке.

Рекомендация: Podman + Podman Compose + systemd

Почему:
- Pod'ы идеально подходят для группировки микросервисов
- Меньше ресурсов на локальной машине
- Легче экспортировать в Kubernetes YAML
- Экспорт как systemd unit файлы для удобства
- Контейнеры запускаются как обычный пользователь

Рекомендуемый workflow:

bash
<h2 id="1-razrabotka-s-podman-compose">1. Разработка с podman-compose</h2>
podman-compose up -d

<h2 id="2-kogda-gotovo-k-razvyortyvaniyu">2. Когда готово к развёртыванию</h2>
podman generate systemd --new > systemd-unit.service

<h2 id="3-eksport-v-kubernetes">3. Экспорт в Kubernetes</h2>
podman play kube pod.yaml
<h2 id="ili">или</h2>
podman generate kube > pod.yaml
kubectl apply -f pod.yaml


Сценарий 8: Гибридное окружение, gradual migration

У вас есть система на Docker, но вы хотите постепенно мигрировать на Podman.

Рекомендация: Hybrid approach (Docker + Podman)

Как это работает:

bash
<h2 id="1-ustanovit-obe-platformy-oni-sovmestimy">1. Установить обе платформы (они совместимы)</h2>
<h2 id="docker-ostayotsya-dlya-legacy-prilozheniy">Docker остаётся для legacy приложений</h2>
<h2 id="podman-ispolzuetsya-dlya-novyh-prilozheniy">Podman используется для новых приложений</h2>

<h2 id="2-ispolzovat-podman-api-sovmestimost">2. Использовать Podman API совместимость</h2>
podman system service --time=0 unix:///run/podman/podman.sock &
export DOCKER_HOST=unix:///run/podman/podman.sock

<h2 id="3-docker-instrumenty-ispolzuyut-podman">3. Docker инструменты используют Podman</h2>
docker ps # Показывает Podman контейнеры

<h2 id="4-postepennaya-migratsiya-odin-servis-za-raz">4. Постепенная миграция один сервис за раз</h2>
<h2 id="legacy-service-1-ostayotsya-na-docker">- Legacy Service 1: остаётся на Docker</h2>
<h2 id="legacy-service-2-ostayotsya-na-docker">- Legacy Service 2: остаётся на Docker</h2>
<h2 id="new-service-a-migrirovan-na-podman">- New Service A: мигрирован на Podman</h2>
<h2 id="new-service-b-razrabotan-na-podman">- New Service B: разработан на Podman</h2>


Этот подход:
- Минимизирует риск
- Позволяет обучать команду постепенно
- Новые сервисы используют лучшие практики (Podman)
- Legacy сервисы остаются стабильными



Пошаговая миграция с Docker на Podman


Если вы решили мигрировать с Docker на Podman, вот детальное пошаговое руководство, которое минимизирует риск потери данных и downtime.

Этап 1: Планирование и оценка (2-3 дня)

Первый и критически важный шаг.

bash
<h2 id="dokumentirovat-tekuschee-sostoyanie">Документировать текущее состояние</h2>

<h2 id="vse-konteynery">Все контейнеры</h2>
docker ps -a > containers.txt

<h2 id="vse-obrazy">Все образы</h2>
docker images > images.txt

<h2 id="vse-volumes">Все volumes</h2>
docker volume ls > volumes.txt

<h2 id="vse-seti">Все сети</h2>
docker network ls > networks.txt

<h2 id="vse-docker-compose-fayly">Все docker-compose файлы</h2>
find . -name "docker-compose.yml" > compose-files.txt

<h2 id="versii">Версии</h2>
docker --version > versions.txt
docker-compose --version >> versions.txt

<h2 id="razmer-volumes">Размер volumes</h2>
du -sh /var/lib/docker/volumes/* > volume-sizes.txt

<h2 id="konfiguratsiya-daemon">Конфигурация daemon</h2>
cat /etc/docker/daemon.json > docker-daemon-config.json


Также документировать:
- Зависимости между сервисами
- Критичность каждого сервиса (SLA)
- Требования по downtime (можно ли остановить?)
- Время миграции (ночь? выходной? плановое окно?)

Этап 2: Проверка совместимости (1-2 дня)

Проверить, что приложения будут работать в Podman.

bash
<h2 id="dlya-kazhdogo-konteynera-obraza-proverit-sovmestimost">Для каждого контейнера/образа, проверить совместимость</h2>

<h2 id="skachat-obrazy-v-podman">Скачать образы в Podman</h2>
podman pull my-image:latest
podman pull postgres:15
podman pull redis:7
podman pull nginx:latest

<h2 id="testirovat-kazhdyy-obraz">Тестировать каждый образ</h2>
podman run --rm my-image:latest echo "test"
podman run --rm postgres:15 postgres --version
podman run --rm redis:7 redis-cli --version

<h2 id="dlya-docker-compose-faylov">Для docker-compose файлов</h2>
podman-compose -f docker-compose.yml pull

<h2 id="proverit-na-docker-spetsifichnye-funktsii">Проверить на Docker-специфичные функции</h2>
grep -r "docker" docker-compose.yml # Может быть проблема
grep -r "dind" docker-compose.yml # Docker-in-Docker не работает
grep -r "privileged" docker-compose.yml # Нужна осторожность


Создать список потенциальных проблем и решений.

Этап 3: Подготовка окружения (1 день)

Установить Podman на целевую систему.

bash
<h2 id="na-sisteme-kuda-migriruem">На системе, куда мигрируем</h2>

<h2 id="obnovit-pakety">Обновить пакеты</h2>
sudo apt update

<h2 id="ustanovit-podman">Установить Podman</h2>
sudo apt install -y podman podman-compose

<h2 id="proverit-ustanovku">Проверить установку</h2>
podman --version
podman run hello-world

<h2 id="ubeditsya-chto-rootless-rezhim-rabotaet">Убедиться что rootless режим работает</h2>
podman info | grep rootless
<h2 id="dolzhno-byt-rootless-true">Должно быть: rootless: true</h2>

<h2 id="nastroit-registr-dlya-dostupa-k-privatnym-registram-esli-ispolzuyutsya">Настроить регистр для доступа к приватным регистрам (если используются)</h2>
<h2 id="otredaktirovat-config-containers-registries-conf">Отредактировать ~/.config/containers/registries.conf</h2>
podman login registry.company.com # Если требуется аутентификация


Этап 4: Миграция образов (несколько часов)

Перенести все Docker образы в Podman.

bash
<h2 id="variant-1-dlya-obrazov-v-docker-hub-ili-public-registry">Вариант 1: Для образов в Docker Hub или public registry</h2>
podman pull my-app:1.0
podman pull postgres:15
podman pull redis:7

<h2 id="variant-2-eksportirovat-obrazy-iz-docker-lokalno">Вариант 2: Экспортировать образы из Docker локально</h2>
<h2 id="esli-obrazy-tolko-lokalnye-ili-nuzhen-pryamoy-kontrol">(если образы только локальные или нужен прямой контроль)</h2>

docker save my-app:1.0 | podman load
docker save postgres:15 | podman load
docker save redis:7 | podman load

<h2 id="ili-skript-dlya-vseh-obrazov">Или скрипт для всех образов</h2>
docker images --format "{{.Repository}}:{{.Tag}}" | while read image; do
echo "Migrating $image"
docker save "$image" | podman load
done

<h2 id="proverit-chto-vse-obrazy-zagruzheny">Проверить что все образы загружены</h2>
podman images


Этап 5: Миграция контейнеров (1-2 дня)

Для каждого контейнера, запустить его с Podman.

bash
<h2 id="dlya-prostyh-konteynerov-dostatochno-zamenit-docker-na-podman">Для простых контейнеров достаточно заменить docker на podman</h2>

<h2 id="bylo">Было</h2>
docker run -d --name web -p 8080:80 -v web_data:/app/data \
--env-file .env nginx:latest

<h2 id="stalo">Стало</h2>
podman run -d --name web -p 8080:80 -v web_data:/app/data \
--env-file .env nginx:latest

<h2 id="protestirovat-chto-konteyner-rabotaet">Протестировать что контейнер работает</h2>
podman logs -f web

<h2 id="proverit-chto-usluga-dostupna">Проверить что услуга доступна</h2>
curl http://localhost:8080

<h2 id="esli-vsyo-rabotaet-udalit-staryy-docker-konteyner">Если всё работает, удалить старый Docker контейнер</h2>
docker stop web
docker rm web


Этап 6: Миграция docker-compose (1-2 дня)

Для проектов использующих docker-compose.

bash
<h2 id="testirovat-docker-compose-fayl-s-podman-compose">Тестировать docker-compose файл с Podman Compose</h2>

<h2 id="shag-1-skachat-vse-obrazy">Шаг 1: Скачать все образы</h2>
podman-compose -f docker-compose.yml pull

<h2 id="shag-2-zapustit-servisy-v-testovom-rezhime">Шаг 2: Запустить сервисы (в тестовом режиме)</h2>
podman-compose -f docker-compose.yml up -d

<h2 id="shag-3-proverit-logi-i-status">Шаг 3: Проверить логи и статус</h2>
podman-compose logs -f
podman-compose ps

<h2 id="shag-4-protestirovat-funktsionalnost-prilozheniya">Шаг 4: Протестировать функциональность приложения</h2>
<h2 id="proverit-endpoints">- Проверить endpoints</h2>
<h2 id="proverit-bd-dostupna">- Проверить БД доступна</h2>
<h2 id="proverit-chto-dannye-sohranyayutsya">- Проверить что данные сохраняются</h2>

<h2 id="shag-5-ostanovit-i-proverit-that-all-stops-cleanly">Шаг 5: Остановить и проверить that all stops cleanly</h2>
podman-compose down

<h2 id="shag-6-esli-vsyo-rabotaet-ostanovit-starye-docker-konteynery">Шаг 6: Если всё работает, остановить старые Docker контейнеры</h2>
docker-compose down

<h2 id="shag-7-zapustit-podman-versiyu-v-production">Шаг 7: Запустить Podman версию в production</h2>
podman-compose -f docker-compose.yml up -d


Этап 7: Миграция данных (критично!)

Для сервисов с важными данными, нужен backup и restore.

bash
<h2 id="dlya-kazhdogo-volume-s-vazhnymi-dannymi">Для каждого volume с важными данными</h2>

<h2 id="shag-1-sozdat-backup-iz-docker">Шаг 1: Создать backup из Docker</h2>
docker run --rm -v important_data:/data -v $(pwd):/backup \
alpine tar czf /backup/important_data_backup.tar.gz /data

<h2 id="shag-2-sozdat-novyy-volume-v-podman">Шаг 2: Создать новый volume в Podman</h2>
podman volume create important_data

<h2 id="shag-3-vosstanovit-dannye-v-podman-volume">Шаг 3: Восстановить данные в Podman volume</h2>
podman run --rm -v important_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/important_data_backup.tar.gz -C /

<h2 id="shag-4-proverit-chto-dannye-vosstanovleny">Шаг 4: Проверить что данные восстановлены</h2>
podman run --rm -v important_data:/data alpine ls -la /data

<h2 id="shag-5-zapustit-konteyner-s-vosstanovlennym-volume">Шаг 5: Запустить контейнер с восстановленным volume</h2>
podman run -d -v important_data:/app/data my-app:latest

<h2 id="shag-6-proverit-chto-prilozhenie-vidit-dannye">Шаг 6: Проверить что приложение видит данные</h2>
podman logs container-name


Этап 8: Обновление CI/CD (1-2 дня)

Обновить все пайплайны, которые используют Docker.

yaml
<h2 id="github-actions-primer">GitHub Actions пример</h2>

<h2 id="bylo">Было</h2>
- name: Build with Docker
run: |
docker build -t myregistry.com/app:${{ github.sha }} .
docker push myregistry.com/app:${{ github.sha }}

<h2 id="stalo">Стало</h2>
- name: Build with Podman
run: |
podman build -t myregistry.com/app:${{ github.sha }} .
podman push myregistry.com/app:${{ github.sha }}


yaml
<h2 id="gitlab-ci-primer">GitLab CI пример</h2>

<h2 id="bylo">Было</h2>
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t app:latest .
- docker push registry.gitlab.com/project/app:latest

<h2 id="stalo">Стало</h2>
build:
stage: build
image: podman:latest
script:
- podman build -t app:latest .
- podman push registry.gitlab.com/project/app:latest


Этап 9: Обновление документации (1 день)

Обновить все документы, README файлы и wiki.

markdown
<h2 id="bylo">Было</h2>
<h2 id="zapusk-servisa">Запуск сервиса</h2>

docker-compose up -d

<h2 id="prosmotr-logov">Просмотр логов</h2>

docker logs service-name

<h2 id="stalo">Стало</h2>
<h2 id="zapusk-servisa">Запуск сервиса</h2>

podman-compose up -d

<h2 id="prosmotr-logov">Просмотр логов</h2>

podman logs service-name


Также:
- Обновить инструкции по запуску на локальной машине
- Обновить инструкции по развёртыванию
- Обновить troubleshooting гайды
- Обновить требования к окружению

Этап 10: Финальная проверка и откат (1 день)

Перед финальным switch'ем, провести финальную проверку.

bash
<h2 id="finalnyy-checklist">Финальный checklist</h2>

<h2 id="vse-konteynery-rabotayut-v-podman">[ ] Все контейнеры работают в Podman</h2>
<h2 id="vse-dannye-uspeshno-migrirovany">[ ] Все данные успешно мигрированы</h2>
<h2 id="vse-funktsii-prilozheniya-rabotayut">[ ] Все функции приложения работают</h2>
<h2 id="vse-zavisimosti-mezhdu-servisami-rabotayut">[ ] Все зависимости между сервисами работают</h2>
<h2 id="vse-endpoints-dostupny">[ ] Все endpoints доступны</h2>
<h2 id="logirovanie-rabotaet">[ ] Логирование работает</h2>
<h2 id="monitoring-rabotaet">[ ] Мониторинг работает</h2>
<h2 id="backup-restore-rabotaet">[ ] Backup/restore работает</h2>
<h2 id="ci-cd-payplayny-rabotayut">[ ] CI/CD пайплайны работают</h2>
<h2 id="dokumentatsiya-obnovlena">[ ] Документация обновлена</h2>
<h2 id="komanda-obuchena">[ ] Команда обучена</h2>

<h2 id="esli-vsyo-ok-finalnyy-switch">Если всё OK, финальный switch:</h2>

<h2 id="1-ostanovit-docker-versiyu">1. Остановить Docker версию</h2>
sudo systemctl stop docker

<h2 id="2-ubeditsya-chto-podman-versiya-rabotaet">2. Убедиться что Podman версия работает</h2>
podman-compose ps

<h2 id="3-esli-chto-to-poshlo-ne-tak-bystryy-otkat">3. Если что-то пошло не так, быстрый откат:</h2>
<h2 id="vklyuchit-docker-obratno">Включить Docker обратно</h2>
sudo systemctl start docker

<h2 id="4-esli-net-problem-otklyuchit-docker">4. Если нет проблем, отключить Docker</h2>
sudo systemctl disable docker




Часто задаваемые вопросы (FAQ)


Вопрос 1: Какой инструмент быстрее — Docker или Podman?

Различие в производительности менее 5% в большинстве сценариев. Docker и Podman используют одинаковые Linux технологии (namespaces, cgroups). Выбирайте на основе других факторов (безопасность, удобство, совместимость). Podman может быть быстрее в создании контейнеров (10-15%) потому что не требует подключения к daemon'у.

Вопрос 2: Могу ли я использовать Docker и Podman одновременно?

Да, возможно. Docker daemon и Podman могут работать рядом в одной системе. Они используют разные сокеты и хранилище образов, поэтому не конфликтуют. Однако это добавляет сложность. Образы Docker не видны в Podman и наоборот. Рекомендуется использовать один инструмент на одной системе, или использовать Podman API совместимость.

Вопрос 3: Поддерживает ли Podman Docker Hub?

Да, полностью. `podman pull`, `podman push` работают с Docker Hub и любыми OCI-совместимыми регистрами (Quay.io, AWS ECR, Google Artifact Registry, Azure Container Registry, etc).

Вопрос 4: Как мне перенести Docker образы на Podman?

Несколько вариантов:
1. Скачать из registry: `podman pull image:tag`
2. Экспортировать из Docker: `docker save image | podman load`
3. Скрипт для всех образов: `docker images --format "{{.Repository}}:{{.Tag}}" | xargs -I {} sh -c 'docker save {} | podman load'`

Вопрос 5: Есть ли GUI для Podman?

Да, Podman Desktop (https://podman.io/desktop) — это GUI для Podman, аналог Docker Desktop. Доступен для macOS, Windows и Linux. Позволяет управлять контейнерами, образами, volumes через интерфейс.

Вопрос 6: Какие CI/CD системы поддерживают Podman?

Современные: GitHub Actions (через actions), GitLab CI, Jenkins (через plugin), CircleCI, Travis CI, Azure Pipelines, AWS CodeBuild. Обычно достаточно установить Podman в runner и использовать `podman` вместо `docker`.

Вопрос 7: Требует ли Podman sudo?

Нет, Podman работает как обычный пользователь (rootless режим по умолчанию). Это главное преимущество безопасности.

Вопрос 8: Могу ли я использовать docker-compose файл с Podman?

Не напрямую, но используйте `podman-compose`, который совместим с docker-compose.yml файлами. Синтаксис почти идентичен.

Вопрос 9: Что такое Buildah и как он связан с Podman?

Buildah — инструмент для построения OCI образов, создан Red Hat. Podman использует Buildah под капотом для `podman build`. Для большинства пользователей `podman build` достаточно.

Вопрос 10: Является ли Podman безопаснее Docker?

Да, rootless режим по умолчанию безопаснее. User namespace isolation предотвращает эскалацию привилегий. Но в production оба могут быть безопасны с правильной конфигурацией и practices.

Вопрос 11: Может ли Podman работать в production?

Да, полностью. Podman используется в production у многих компаний, особенно в Red Hat-based окружениях (OpenShift). Уже используется в production в финансовом секторе и государственных организациях.

Вопрос 12: Есть ли инструменты мониторинга для Podman?

Да: cAdvisor собирает статистику контейнеров, Prometheus может мониторить Podman API, Portainer имеет поддержку Podman, Grafana для визуализации. Большинство инструментов для Docker также работают с Podman через API.

Вопрос 13: Что такое rootless режим?

Rootless режим означает, что контейнеры могут запускаться как обычный пользователь (не root). Контейнер видит себя как root внутри (благодаря user namespace), но на хост-системе это непривилегированный процесс. Это безопаснее.

Вопрос 14: Как сделать Podman совместимым с Docker инструментами?

Запустить Podman в режиме совместимости с Docker API:
bash
podman system service --time=0 unix:///run/podman/podman.sock &
export DOCKER_HOST=unix:///run/podman/podman.sock

Теперь `docker` команды используют Podman.

Вопрос 15: Какой инструмент я должен выбрать для моего проекта?

Руководство:
- Подстав: Podman (новые проекты, лучше безопасность)
- Нет причин менять: Docker (если инвестиции уже есть)
- Обязательно Podman: финансовые системы, госслужбы, high-security
- Обязательно Docker: если используете специфичные инструменты, которые только на Docker

Вопрос 16: Будет ли Docker существовать в 2027 году?

Да, Docker остаётся стандартом и будет существовать. Но Podman будет расти в популярности, особенно в enterprise и high-security окружениях. Оба инструмента будут актуальны.



Заключение и рекомендации для 2026


К 2026 году Docker и Podman — оба зрелые, стабильные платформы контейнеризации. Docker остаётся де-факто стандартом благодаря многолетней инерции, огромной экосистеме, сообществу и поддержке облачных платформ. Podman представляет собой серьёзную, продуманную альтернативу с явными преимуществами в безопасности, гибкости и интеграции с Linux экосистемой.

Выбор Docker, если:
- Вы начинаете путь в контейнеризации (лучше документация, обучающие материалы, сообщество)
- Требуется максимальная совместимость с существующими инструментами и сервисами
- Ваша команда полностью обучена Docker и привыкла к нему
- Вы работаете с облачными платформами, оптимизированными под Docker (AWS ECS, Google Cloud Run)
- Вам нужны специализированные инструменты, доступные только в Docker экосистеме

Выбор Podman, если:
- Безопасность критична для вашего проекта (финансы, госслужбы, критическая инфраструктура)
- Вы работаете в multi-user окружении (CI/CD с несколькими пользователями)
- Вам требуется rootless режим
- Вы разрабатываете для Kubernetes или OpenShift
- Вы разрабатываете локально на машине с ограниченными ресурсами (ноутбук, IoT)
- Требуется лучшая интеграция с systemd и Linux инструментами

Гибридный подход:
Многие организации успешно используют обе платформы:
- Docker для legacy приложений
- Podman для новых приложений
- Postепенная миграция один сервис за раз
- Использование Podman API совместимости для инструментов

Тренды на 2026 и далее:

1. Kubernetes доминирует — для production приложений большинство компаний используют Kubernetes для управления контейнерами. Выбор между Docker и Podman становится менее критичным, потому что оба работают с Kubernetes.

2. Подконтейнерные runtime'ы (containerd, CRI-O) — становятся стандартом. Docker daemon и Podman по умолчанию используют эти runtime'ы.

3. Безопасность в фокусе — Podman набирает популярность именно благодаря лучшей безопасности по умолчанию. Финансовые и государственные организации выбирают Podman.

4. DevOps аутоматизация — инструменты становятся всё более agnostic к выбору Docker/Podman. Фокус на infrastructure-as-code и automation.

5. Контейнеризация на примеры — контейнеризация не исчезнет, но может эволюционировать (WebAssembly контейнеры, unikernels и т.д.).

Финальные рекомендации:

1. Инвестируйте в знания, не в инструменты — знание Linux, контейнеризации, Kubernetes, networking остаётся релевантным независимо от выбора Docker vs Podman.

2. Выбирайте инструмент под конкретную задачу — не учитывайте общие рекомендации, если у вас специфичный use case.

3. Оставайтесь гибкими — это не одноразовое решение. Технологии эволюционируют, и то, что правильно в 2026, может потребовать пересмотра в 2028.

4. Миграция — это процесс, не событие — если вы решили мигрировать, делайте это постепенно, тестируйте каждый шаг, имейте план отката.

5. Безопасность превыше всего — особенно в production окружениях. Корректная конфигурация и practices важнее выбора инструмента.

6. Сообщество и поддержка — проверяйте, есть ли у инструмента активное сообщество, документация, поддержка для вашего use case'а.

В заключении: (#заключение)

И Docker, и Podman — оба отличные инструменты. Docker изменил мир разработки 13 лет назад, и это положение на рынке заслужено. Podman — более молодой, но тщательно спроектированный инструмент, который решает некоторые проблемы Docker и предлагает новые возможности.

Выбирайте инструмент, который лучше всего соответствует вашим потребностям, но помните, что это не выбор на вечность. Будьте готовы к эволюции и изменениям.

2026 год — это хорошее время для переосмысления инфраструктуры контейнеризации, особенно если у вас есть возможность переиграть с чистого листа или эффективно мигрировать. Но это также хорошее время для признания, что любой из этих инструментов может быть правильным выбором в зависимости от контекста.