# sysrc jail_enable="YES"
# sysrc jail_parallel_start="YES"Глава 17. Клетки и контейнеры
Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.
Содержание
17.1. Обзор
Поскольку администрирование системы — сложная задача, было разработано множество инструментов, чтобы облегчить жизнь администратору. Эти инструменты часто улучшают способы установки, настройки и обслуживания систем. Один из инструментов, который можно использовать для повышения безопасности системы FreeBSD, — это клетки (jails). Клетки доступны начиная с FreeBSD 4.X и продолжают совершенствоваться в плане полезности, производительности, надёжности и безопасности.
Клетки расширяют концепцию chroot(2), которая используется для изменения корневого каталога для набора процессов. Это создаёт безопасное окружение, изолированное от остальной системы. Процессы, созданные в окружении chroot, не могут обращаться к файлам или ресурсам за его пределами. По этой причине компрометация службы, работающей в окружении chroot, не должна позволить злоумышленнику скомпрометировать всю систему.
Однако chroot имеет несколько ограничений. Он подходит для простых задач, не требующих большой гибкости или сложных, продвинутых функций. Со временем было найдено множество способов выйти из окружения chroot, что делает его не самым идеальным решением для защиты сервисов.
Клетки улучшают концепцию традиционной изолированной среды chroot несколькими способами.
В традиционной среде chroot процессы ограничены только в части файловой системы, к которой они могут получить доступ. Остальные системные ресурсы, пользователи системы, запущенные процессы и подсистема сети разделяются между процессами в chroot и процессами основной системы. Клетки расширяют эту модель, виртуализируя доступ к файловой системе, набору пользователей и подсистеме сети. Доступны более детальные настройки для регулирования доступа в изолированной среде. Клетки можно рассматривать как один из видов виртуализации на уровне операционной системы.
Эта глава охватывает:
Что такое клетка и для каких целей он может использоваться в FreeBSD.
Типы клеток.
Различные способы настройки сети для клетки.
Файл конфигурации клетки.
Как создать различные типы клетки.
Как настроить трансляцию сетевых адресов для клеток.
Как запустить, остановить и перезапустить клетку.
Основы администрирования клеток, как изнутри, так и снаружи клетки.
Как обновить различные типы клеток.
Как ограничить ресурсы, которые может использовать клетка.
Дополнительные параметры безопасности и функций на уровне клетки.
Как делегировать клетке наборы данных ZFS.
Неполный список различных менеджеров клеток FreeBSD.
17.2. Типы клеток
Некоторые администраторы разделяют клетки на различные типы, хотя базовые технологии остаются одинаковыми. Каждому администратору необходимо определить, какой тип клетки создавать в каждом конкретном случае, в зависимости от решаемой задачи.
Ниже приведён список различных типов, их характеристики и рекомендации по использованию.
17.2.1. Толстые клетки (Thick Jails)
Толстая клетка (thick jail) — это традиционная форма клетки FreeBSD. В толстой клетке полная копия базовой системы реплицируется внутри окружения клетки. Это означает, что клетка имеет свою собственную отдельную копию базовой системы FreeBSD, включая библиотеки, исполняемые файлы и конфигурационные файлы. Клетку можно рассматривать как почти полноценную автономную установку FreeBSD, но работающую в рамках хост-системы. Такая изоляция гарантирует, что процессы внутри клетки остаются отделёнными от процессов на хосте и в других клетках.
Преимущества толстых клеток:
Высокая степень изоляции: процессы внутри клеток изолированы от хост-системы и других клеток.
Независимость: толстые клетки могут иметь версии библиотек, настройки и программное обеспечение, отличные от хост-системы или других клеток.
Безопасность: поскольку клетка содержит собственную базовую систему, уязвимости или проблемы, затрагивающие среду клетки, не оказывают прямого влияния на хост-систему или другие клетки.
Недостатки толстых клеток:
Ресурсные затраты: поскольку каждая клетка поддерживает свою собственную отдельную базовую систему, толстые клетки потребляют больше ресурсов по сравнению с тонкими клетками.
Обслуживание: каждая клетка требует собственного обслуживания и обновлений для своих базовых системных компонентов.
17.2.2. Тонкие клетки (Thin Jails)
Тонкая клетка использует базовую систему из шаблона, используя либо снимки OpenZFS, либо монтирования NullFS. Для каждой тонкой клетки дублируется лишь минимальный поднабор базовой системы, что приводит к меньшему потреблению ресурсов по сравнению с толстой клеткой. Два механизма ведут себя по-разному после создания клеток. При методе OpenZFS каждая тонкая клетка создается как клон снимка шаблона: независимая копия с записью при копировании, которая разделяет неизмененные блоки с шаблоном, но расходится при изменении. Более поздние изменения шаблона не распространяются на существующие клоны, и каждый клон обслуживается и обновляется индивидуально, во многом как толстая клетка. При методе NullFS каждая тонкая клетка монтирует шаблон только для чтения во время выполнения, поэтому базовая система используется совместно в реальном времени, и обновление шаблона обновляет каждую клетку, которая его монтирует. Эта общая база, доступная только для чтения, также обеспечивает тонким клеткам NullFS меньшую изоляцию и независимость, чем толстым клеткам, поскольку изменения в общих компонентах одновременно затрагивают каждую клетку, использующую их.
Вкратце, тонкая клетка в FreeBSD — это тип клетки FreeBSD, который воспроизводит значительную часть, но не всю базовую систему, в изолированной среде.
Преимущества тонких клеток:
Эффективность использования ресурсов: тонкие клетки более эффективны в использовании ресурсов по сравнению с толстыми клетками. Поскольку они используют общую базовую систему, они занимают меньше места на диске и оперативной памяти. Это позволяет запускать больше клеток на том же оборудовании без чрезмерного потребления ресурсов.
Быстрое развёртывание: создание и запуск тонких клеток обычно происходит быстрее по сравнению с толстыми клетками. Это может быть особенно полезно при быстром развертывании множества экземпляров.
Унифицированное обслуживание: используя метод NullFS, когда тонкие клетки используют одну копию базовой системы, доступную для чтения, обновления и обслуживание общих компонентов базовой системы (таких как библиотеки и исполняемые файлы) необходимо выполнять только один раз на шаблоне. Это упрощает процесс обслуживания по сравнению с поддержкой отдельной базовой системы для каждой толстой клетки. Тонкие клетки в клоне OpenZFS не обладают таким преимуществом: так как каждый клон независим, обновление должно быть применено к каждой клетке индивидуально, как и в случае с толстыми клетками.
Общие ресурсы: тонкие клетки могут проще разделять общие ресурсы, такие как библиотеки и исполняемые файлы, с хост-системой. Это может привести к более эффективному использованию кэширования диска и повышению производительности приложений внутри клетки.
Недостатки тонких клеток:
Уменьшенная изоляция: основной недостаток тонких клеток заключается в том, что они обеспечивают меньшую изоляцию по сравнению с толстыми клетками. В частности клетки с методом NullFS пользуются копией базовой системы шаблона в реальном времени, поэтому уязвимости или проблемы, затрагивающие эти общие компоненты, могут потенциально повлиять на несколько клеток одновременно.
Проблемы безопасности: уменьшенная изоляция в тонких клетках может представлять угрозу безопасности, так как компрометация одной клетки может с большей вероятностью повлиять на другие клетки или на хост-систему.
Конфликты зависимостей: если нескольким тонким клеткам требуются разные версии одних и тех же библиотек или программного обеспечения, управление зависимостями может усложниться. В некоторых случаях это может потребовать дополнительных усилий для обеспечения совместимости.
Проблемы совместимости: приложения в тонкой клетке могут столкнуться с проблемами совместимости, если они рассчитаны на определённое окружение базовой системы, отличающееся от общих компонентов, предоставляемых шаблоном.
17.2.3. Сервисные клетки (Service Jails)
Сервисная клетка (service jail) напрямую разделяет всё дерево файловой системы с хостом (корневой путь клетки — /) и, таким образом, может получать доступ и изменять любые файлы на хосте, а также использует те же учётные записи пользователей, что и хост. По умолчанию у неё нет доступа к сети или другим ресурсам, ограниченным в клетках, но её можно настроить для повторного использования сети хоста и снятия некоторых ограничений клетки. Основное применение сервисных клеток — автоматическое ограничение служб/демонов внутри клетки с минимальной настройкой и без необходимости знания файлов, требуемых такой службой/демоном. Сервисные клетки доступны с версии FreeBSD 15.0.
Преимущества сервисных клеток:
Нулевое администрирование: для службы, готовой к использованию в клетке, достаточно одной строки конфигурации в /etc/rc.conf, для службы, не готовой к использованию в клетке, требуется две строки конфигурации.
Ресурсоэффективность: сервисные клетки более эффективны в использовании ресурсов, чем тонкие клетки, так как они не требуют дополнительного дискового пространства или сетевых ресурсов.
Быстрое развёртывание: создание и запуск сервисных клеток обычно выполняется быстрее по сравнению с тонкими клетками, если требуется изолировать только отдельные сервисы/демоны и не нужны параллельные экземпляры одного и того же сервиса/демона.
Общие ресурсы: сервисные клетки разделяют все ресурсы, такие как библиотеки и исполняемые файлы, с хост-системой. Это может привести к более эффективному использованию кэширования диска и повышению производительности приложений внутри клетки.
Изоляция процессов: сервисные клетки изолируют определённую службу, она не может видеть процессы, которые не являются дочерними по отношению к этой сервисной клетке, даже если они выполняются в рамках той же учётной записи пользователя.
Недостатки сервисных клеток:
Уменьшенная изоляция: основной недостаток сервисных клеток заключается в отсутствии изоляции файловой системы по сравнению с толстой или тонкой клеткой.
Проблемы безопасности: уменьшенная изоляция в сервисных клетках может создавать угрозы безопасности, поскольку компрометация одной клетки потенциально способна сильнее повлиять на всё в хост-системе.
Большая часть настройки клеток, обсуждаемая ниже, не требуется для сервисных клеток. Чтобы понять, как работают клетки, рекомендуется разобраться в этих возможностях конфигурации. Подробности о том, что необходимо для настройки сервисной клетки, приведены в разделе Настройка сервисных клеток.
17.2.4. Клетки VNET
Клетка FreeBSD VNET — это виртуализированная среда, которая обеспечивает изоляцию и контроль сетевых ресурсов для процессов, выполняющихся внутри неё. Она предоставляет высокий уровень сетевой сегментации и безопасности, создавая отдельный сетевой стек для процессов внутри клетки, что гарантирует изоляцию сетевого трафика внутри клетки от хост-системы и других клеток.
По сути, механизм VNET в FreeBSD добавляет возможность настройки сети. Это означает, что клетку VNET можно создать как толстой, так и тонкой.
17.2.5. Клетки Linux
Клетки Linux в FreeBSD — это функция в операционной системе FreeBSD, которая позволяет использовать исполняемые файлы Linux и приложения внутри клетки FreeBSD. Эта функциональность достигается за счёт совместимости, которая позволяет транслировать и выполнять определённые системные вызовы Linux и использовать библиотеки Linux с ядром FreeBSD. Цель клеток Linux — облегчить выполнение Linux-программ в системе FreeBSD без необходимости в отдельной виртуальной машине или среде Linux.
17.3. Конфигурация хоста
Прежде чем создавать клетку на хост-системе, необходимо выполнить определённые настройки и получить некоторую информацию от хост-системы.
Потребуется настроить утилиту jail(8), создать необходимые каталоги для настройки и установки клетки, получить информацию о сети хоста и проверить, использует ли хост файловую систему OpenZFS или UFS.
Версия FreeBSD, работающая в клетке, не может быть новее версии, работающей на хосте. |
17.3.1. Утилита jail
Утилита jail(8) управляет клетками.
Чтобы запускать клетки при загрузке системы, выполните следующие команды:
С |
По умолчанию каждая клетка, которая имеет запись в конфигурационных файлах, запускается при загрузке. Чтобы запустить только выбранные клетки, перечислите их имена в jail_list:
# sysrc jail_list="www db"Имена в jail_list разделяются пробелами и должны соответствовать именам клеток, определённым в /etc/jail.conf или /etc/jail.conf.d/. При загрузке запускаются только перечисленные клетки, и они запускаются в указанном порядке, поэтому любую клетку, пропущенную в jail_list, необходимо запускать вручную. Когда jail_list остаётся пустым, запускаются все клетки, определённые в файлах конфигурации.
Чтобы остановить клетки в обратном порядке их jail_list при завершении работы, установите jail_reverse_stop:
# sysrc jail_reverse_stop="YES"С включённым |
17.3.2. Сетевое взаимодействие
Сеть для клеток FreeBSD может быть настроена несколькими различными способами:
- Режим сетевого взаимодействия хоста (разделение IP)
В режиме сетевого доступа хоста клетка использует сетевой стек хост-системы, а не получает собственный. Совместное использование стека не означает совместное использование адреса: распространённая настройка предоставляет клетке собственный выделенный
ip4.addr(иip6.addr), который jail(8) добавляет как псевдоним на интерфейсе хост-системы, поэтому клетка и хост-система отвечают на разных адресах через один и тот же стек. Только клетка, настроенная сip4 = inherit, полностью видит и может пользоваться адресами хост-системы и отвечает на собственном адресе хост-системы, получая неограниченный доступ ко всем адресам, которыми владеет хост-система.- Виртуальные сети (VNET)
Виртуальные сети (VNET) — это функция клеток FreeBSD, предоставляющая более продвинутые и гибкие сетевые решения по сравнению с базовыми режимами, такими как режим сетевого взаимодействия хоста (host networking). VNET позволяет создавать изолированные сетевые стеки для каждой клетки, предоставляя им отдельные IP-адреса, таблицы маршрутизации и сетевые интерфейсы. Это обеспечивает более высокий уровень сетевой изоляции и позволяет клеткам функционировать так, как если бы они работали на отдельных виртуальных машинах.
- Система netgraph
netgraph(4) — это универсальная инфраструктура ядра для создания пользовательских сетевых конфигураций. Она может использоваться для определения того, как сетевой трафик передаётся между клеткой и хост-системой, а также между различными клетками.
17.3.2.1. Откуда берется IP-адрес клетки
Клетка с общим стеком получает доступ к сети через адрес на интерфейсе хоста. В параметре interface указывается имя этого интерфейса, и для каждого адреса в ip4.addr и ip6.addr jail(8) сам управляет псевдонимом: как выражается jail(8), «псевдоним для каждого адреса будет добавлен к интерфейсу до создания клетки и будет удалён из интерфейса после удаления клетки». Ничто на хост-системе не обязано предварительно настраивать адрес.
Интерфейс также может быть указан для каждого адреса, так что одна строка связывает адрес с интерфейсом, который должен этот адрес использовать:
ip4.addr = "em0|192.168.1.151/24";
Когда адрес должен сохраняться независимо от клетки — потому что другая служба на хост-системе полагается на него, или потому что параметр interface не используется — назначьте его на хост-системе как псевдоним rc.conf и исключите его из управления jail(8):
# sysrc ifconfig_em0_aliases="inet 192.168.1.151/32"Более старая, нумерованная форма ifconfig_em0_alias0="inet 192.168.1.151/32" по-прежнему работает, но форма _aliases предпочтительнее для новых конфигураций, поскольку она позволяет избежать хрупкого требования, чтобы нумерованные псевдонимы образовывали непрерывную последовательность alias0, alias1, alias2.
17.3.2.2. Адреса loopback в клетках с общей IP-адресацией
Клетка с общим стеком не имеет собственного интерфейса loopback. Ядро FreeBSD компенсирует это: в клетке без VNET, когда 127.0.0.1 или ::1 сами по себе не являются адресами клетки, ядро молча переписывает как bind(), так и connect() на адрес loopback на первый ip4.addr или ip6.addr клетки. Это поведение не документировано в jail(8), но оно важно, поскольку несет последствия для безопасности.
Не предполагайте, что привязка службы к |
Стандартным средством смягчения является предоставление клетке частного адреса loopback и указание его первым. Клонируйте выделенный интерфейс loopback на хосте и назначьте ему адрес из диапазона 127.0.0.0/8 (или частный адрес RFC 1918):
# sysrc cloned_interfaces="lo1"
# sysrc ifconfig_lo1="inet 127.0.1.1/32"Затем укажите этот адрес первым в ip4.addr клетки, перед любым маршрутизируемым адресом, чтобы переопределение loopback попадало на частный адрес, а не на адрес, обращённый к локальной сети.
17.3.2.3. Подготовка сервисов хост-системы
Каждый псевдоним адреса клетки разделяет порты хост-системы. Демон хост-системы, привязанный к адресу с подстановочным знаком — показанному как *:port в списках прослушивателей — поэтому также прослушивает каждый псевдоним клетки, и он занимает этот порт прежде, чем собственная служба клетки сможет его заявить. Перед запуском любых клеток проверьте, что хост-система уже прослушивает:
# sockstat -4 -6 -lОграничьте каждый демон, который привязывается к адресу-шаблону, чтобы он использовал только собственный адрес хост-системы и оставлял адреса клеток свободными:
syslogd(8): задайте
syslogd_flags="-ss"в /etc/rc.conf. Одинарный-sуже запускает syslogd в безопасном режиме, чтобы он не прослушивал соединения с удаленных хостов для отправки сообщений журнала; согласно syslogd(8), если-s"указан дважды, сетевой сокет вообще не будет открыт", что также предотвращает отправку syslogd на удаленные хосты.sshd(8): закрепите
ListenAddressна адресе хост-системы в файле /etc/ssh/sshd_config вместо того, чтобы оставлять его с подстановочным знаком(wildcard) по умолчанию.ntpd(8) и sendmail(8): привяжите их к адресу хост-системы также через их собственную конфигурацию.
Для контроля на уровне межсетевого экрана за тем, какие адреса может использовать клетка, см. Межсетевые экраны.
17.3.3. Настройка дерева каталогов клетки
Для файлов клеток не назначено какого-то заранее определённого места.
Некоторые администраторы используют /jail, другие — /usr/jail, а третьи — /usr/local/jails. В этой главе будет использоваться /usr/local/jails.
Помимо каталога /usr/local/jails будут созданы другие каталоги:
media будет содержать сжатые файлы загруженных пользовательских окружений.
templates будет содержать шаблоны при использовании тонких клеток.
containers будет содержать клетки.
При использовании OpenZFS выполните следующие команды для создания наборов данных для этих каталогов:
# zfs create -o mountpoint=/usr/local/jails zroot/jails
# zfs create zroot/jails/media
# zfs create zroot/jails/templates
# zfs create zroot/jails/containersВ данном случае для родительского набора данных использовался |
Создание отдельного дочернего набора данных для каждой клетки в дальнейшем позволяет делать снимки, клоны, квоты и делегирование наборов данных для каждой клетки. Поскольку каталог каждой клетки затем становится собственным набором данных, OpenZFS может как ограничивать, так и гарантировать использование ею дискового пространства с помощью свойств quota и reservation; см. Ограничения ресурсов клетки.
При использовании UFS выполните следующие команды для создания каталогов:
# mkdir /usr/local/jails/
# mkdir /usr/local/jails/media
# mkdir /usr/local/jails/templates
# mkdir /usr/local/jails/containers17.3.4. Файлы конфигурации клетки
Существует два способа настройки клеток.
Первый вариант — добавить запись для каждой клетки в файл /etc/jail.conf. Другой вариант — создать отдельный файл для каждой клетки в каталоге /etc/jail.conf.d/.
В случае, если на хост-системе мало клеток, записи для каждого клетки можно добавить в файл /etc/jail.conf. Если на хост-системе много клеток, рекомендуется создать отдельный конфигурационный файл для каждой клетки в каталоге /etc/jail.conf.d/.
Файлы в /etc/jail.conf.d/ должны иметь расширение .conf, и их необходимо подключить в /etc/jail.conf:
.include "/etc/jail.conf.d/*.conf";
Типичная запись с настройками клетки выглядит следующим образом:
jailname { (1)
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc"; (2)
exec.stop = "/bin/sh /etc/rc.shutdown"; (3)
exec.consolelog = "/var/log/jail_console_${name}.log"; (4)
# PERMISSIONS
allow.raw_sockets; (5)
exec.clean; (6)
mount.devfs; (7)
# HOSTNAME/PATH
host.hostname = "${name}"; (8)
path = "/usr/local/jails/containers/${name}"; (9)
# NETWORK
ip4.addr = 192.168.1.151; (10)
ip6.addr = "2001:db8::151"; (11)
interface = em0; (12)
}| 1 | jailname — имя клетки. |
| 2 | exec.start — команда(ы), выполняемые в среде клетки при её создании. Типичная команда для выполнения — "/bin/sh /etc/rc". |
| 3 | exec.stop — команда(ы), выполняемые в среде клетки перед её удалением. Типичная команда для выполнения — "/bin/sh /etc/rc.shutdown". |
| 4 | exec.consolelog — файл для вывода результатов выполнения команды (stdout и stderr). |
| 5 | allow.raw_sockets — разрешает создание raw-сокетов внутри клетки. Установка этого параметра позволяет использовать такие утилиты, как ping(8) и traceroute(8), внутри клетки. |
| 6 | exec.clean — выполнение команд в чистом окружении. |
| 7 | mount.devfs - монтирование файловой системы devfs(5) в каталог /dev внутри chroot, чтобы ограничить видимые в клетке устройства. Применяется набор правил, заданный параметром devfs_ruleset, или, когда этот параметр оставлен по умолчанию равным 0, используется запасной вариант mount.devfs с набором правил 4, devfsrules_jail, который скрывает все устройства хоста, кроме минимального набора, безопасного для клетки (см. Devfs Rulesets). |
| 8 | host.hostname — имя хоста для клетки. |
| 9 | path — каталог, который будет корневым для клетки. Любые команды, выполняемые внутри клетки, либо с помощью jail, либо через jexec(8), запускаются из этого каталога. |
| 10 | ip4.addr - Один IPv4-адрес или разделённый запятыми список адресов, назначенных клетке. Установка ip4.addr подразумевает ip4 = new; сам параметр ip4 не имеет значения по умолчанию (если он не указан, то его значение зависит от значений других параметров). Параметр ip4 принимает три значения: new ограничивает клетку адресами, перечисленными в ip4.addr, inherit предоставляет клетке неограниченный доступ ко всем IPv4-адресам хоста, а disable полностью отключает IPv4 в клетке. Клетка, в которой не заданы ни ip4, ни ip4.addr, ведёт себя как при inherit, и параметры interface и ip4.addr не действуют при inherit. В клетке с несколькими адресами ip4.saddrsel позволяет ядру выбирать исходный адрес для исходящих соединений на несвязанных сокетах, тогда как ip4.nosaddrsel принудительно использует первый адрес из списка. |
| 11 | ip6.addr - Один IPv6-адрес или разделенный запятыми список адресов, назначенных клетке. Параметр ip6 принимает те же значения new, inherit и disable, что и ip4, при этом ip6.saddrsel и ip6.nosaddrsel управляют выбором адреса источника. Используйте ip6 = disable для клетки только с IPv4 или ip4 = disable для клетки только с IPv6. |
| 12 | interface — Сетевой интерфейс для добавления IP-адресов клетки. Обычно это интерфейс хоста. |
Клетка не имеет виртуальной консоли: init(8) и getty(8) не запускаются внутри неё, поэтому не к чему подключиться в интерактивном режиме. Файл |
Файлы /var/log/jail_console_*.log 640 7 100 * J |
17.3.4.1. Глобальные параметры, подстановочные знаки и переменные
Параметры, заданные вне любого блока клетки, являются подстановочными значениями по умолчанию: jail.conf(5) применяет их к каждой клетке, точно так же, как если бы они были записаны в разделе подстановочного знака *. Установка общих параметров один раз делает каждый блок клетки коротким.
Имя, перед которым стоит знак доллара и которое, при необходимости, заключено в фигурные скобки, заменяется значением этого параметра или переменной. Встроенное выражение ${name} разворачивается в собственное имя клетки, а пользовательская переменная определяется точно так же, как параметр, но с ведущим знаком доллара.
Следующий /etc/jail.conf определяет общий заголовок один раз и переопределяет только то, что отличается для каждой клетки:
# Shared defaults applied to every jail
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
exec.clean;
mount.devfs;
host.hostname = "${name}";
path = "/usr/local/jails/containers/${name}";
interface = em0;
www {
ip4.addr = 192.168.1.151;
}
db {
host.hostname = "database.example.com";
ip4.addr = 192.168.1.152;
}Здесь www наследует всё из заголовка и задаёт только свой адрес, тогда как db также переопределяет host.hostname.
17.3.4.2. Командные хуки
jail(8) запускает клетку через последовательность перехватчиков жизненного цикла (хуков), и важно, выполняется ли каждый из хуков в среде хост-системы или внутри клетки. В порядке создания:
exec.prestartВыполняется в среде хост-системы до создания клетки.
exec.createdВыполняется в среде хост-системы после создания клетки, но до запуска любого процесса внутри неё.
exec.startВыполняется внутри клетки, обычно
/bin/sh /etc/rcдля запуска её служб.exec.poststartВыполняется в среде хост-системы после запуска клетки.
При завершении работы хуки выполняется зеркально в обратном порядке:
exec.prestopВыполняется в среде хост-системы до остановки клетки.
exec.stopВыполняется внутри клетки, обычно
/bin/sh /etc/rc.shutdown.exec.poststopВыполняется в среде хост-системы после остановки клетки, чтобы разобрать всё, что было настроено с помощью
exec.prestart.
Хуку может быть назначено более одной команды путём добавления с помощью +=:
exec.poststart += "logger jail ${name} started";exec.timeout ограничивает время, в течение которого jail(8) ожидает завершения команды, а exec.consolelog захватывает вывод этих команд. В разделе VNET (VNET Jails) используются exec.prestart и exec.poststop для настройки и демонтажа сетевой инфраструктуры каждой клетки на хосте.
Тогда как хуки упорядочивают команды внутри одной клетки, параметр depend упорядочивает запуск целых клеток. Запись depend = otherjail; сообщает jail(8), что эта клетка требует otherjail: зависимость создаётся первой, до завершения её последней команды exec.poststart, прежде чем будет создана эта клетка, и клетки уничтожаются в обратном порядке.
17.3.4.3. Наборы правил Devfs
Каждая клетка, которая устанавливает mount.devfs, получает набор правил devfs, определяющий, какие узлы устройств появляются в её /dev: либо тот, который задан параметром devfs_ruleset, либо, когда этот параметр не установлен, значение по умолчанию для mount.devfs — набор правил 4. devfs.rules(5) определяет именованные наборы правил в /etc/defaults/devfs.rules. Два из них предназначены для клеток: devfsrules_jail, набор правил 4, является стандартным минимальным набором устройств для клетки, а devfsrules_jail_vnet, набор правил 5, добавляет /dev/pf, чтобы клетка VNET могла запускать собственный межсетевой экран. Примеры клеток VNET устанавливают devfs_ruleset = 5, а пример клетки Linux устанавливает devfs_ruleset = 4; примеры классической и тонкой клеток устанавливают только mount.devfs и поэтому используют его значение по умолчанию — набор правил 4.
Чтобы открыть доступ к дополнительному устройству, напишите пользовательский набор правил в /etc/devfs.rules, который включает один из стандартных наборов правил и показывает то, что ему необходимо. Следующий набор правил начинается с devfsrules_jail и дополнительно показывает устройства bpf(4):
[devfsrules_jail_bpf=100] add include $devfsrules_jail add path 'bpf*' unhide
Перезагрузите правила, затем укажите новый набор правил по его номеру в конфигурации клетки:
# service devfs restartdevfs_ruleset = 100;
Правила в /etc/devfs.rules переопределяют правила с теми же номерами в /etc/defaults/devfs.rules; в остальных случаях эффект двух файлов фактически объединяется.
Дополнительную информацию о переменных конфигурации можно найти в jail(8) и jail.conf(5).
17.4. Классическая клетка (Толстая клетка)
Эти клетки напоминают настоящую систему FreeBSD. Ими можно управлять почти так же, как обычной хост-системой, и обновлять независимо.
17.4.1. Создание классической клетки
В принципе, для клетки требуется только имя хоста, корневой каталог, IP-адрес и пользовательское пространство.
Пользовательское окружение для клетки можно получить с официальных серверов загрузки FreeBSD.
Выполните следующую команду, чтобы загрузить пользовательское окружение:
# fetch https://download.freebsd.org/releases/amd64/amd64/15.1-RELEASE/base.txz -o /usr/local/jails/media/15.1-RELEASE-base.txzПосле завершения загрузки необходимо извлечь содержимое в каталог клетки.
Выполните следующие команды, чтобы извлечь пользовательское окружение в каталог клетки:
# mkdir -p /usr/local/jails/containers/classic
# tar -xf /usr/local/jails/media/15.1-RELEASE-base.txz -C /usr/local/jails/containers/classic --unlinkС извлечённой пользовательской средой в каталоге клетки потребуется скопировать файлы часового пояса и DNS-сервера:
# cp /etc/resolv.conf /usr/local/jails/containers/classic/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/containers/classic/etc/localtimeСкопировав файлы, следующим шагом будет обновление до последнего уровня исправлений с помощью выполнения следующей команды:
# freebsd-update -b /usr/local/jails/containers/classic/ fetch installПоследним шагом является настройка клетки. Необходимо добавить запись в конфигурационный файл /etc/jail.conf или в jail.conf.d с параметрами клетки.
Пример может выглядеть следующим образом:
classic {
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
# HOSTNAME/PATH
host.hostname = "${name}";
path = "/usr/local/jails/containers/${name}";
# NETWORK
ip4.addr = 192.168.1.151;
interface = em0;
}Выполните следующую команду для запуска клетки:
# service jail start classicДополнительная информация об управлении клетками приведена в разделе Управление клетками.
17.4.2. Получение пользовательского окружения клетки
Процедура fetch-and-extract, показанная выше, является традиционным способом заполнения корневого каталога клетки, но это не единственный способ. Та же самая пользовательская среда может быть установлена с помощью bsdinstall(8), из базовых системных пакетов или из локально собранного дерева исходных кодов.
bsdinstall(8) предоставляет выделенную цель jail, которая настраивает новое пользовательское окружение в заданном каталоге для использования с jail(8). Она загружает и распаковывает наборы дистрибутивов без установки ядра, пропуская шаги разбиения диска и настройки сети обычной установки, что делает её однокомандным скриптом — альтернативой ручной последовательности загрузки и tar(1) следующим образом:
# bsdinstall jail /usr/local/jails/containers/classicЦель jail по умолчанию устанавливает базовый дистрибутив (base.txz). Начиная с FreeBSD 15.0 и более поздних версий, bsdinstall(8) также может заполнять корневой каталог пакетами базовой системы с помощью своей цели pkgbase; метод на основе пакетов описан далее.
Начиная с FreeBSD 15.0, базовая система также публикуется в виде пакетов, поэтому пользовательское окружение клетки можно установить полностью с помощью pkg(8) из репозитория FreeBSD-base. Укажите pkg(8) на корневой каталог клетки с помощью глобальной опции --rootdir и установите вариант клетки для базового набора:
# pkg --rootdir /usr/local/jails/containers/classic install -r FreeBSD-base FreeBSD-set-base-jailИспользуйте FreeBSD-set-minimal-jail вместо FreeBSD-set-base-jail для минимального пользовательского окружения. Клетка, установленная таким образом, впоследствии обновляется и получает исправления с помощью pkg(8), а не freebsd-update(8); см. Обновление клеток pkgbase.
Пакеты базовой системы — это технологическая предварительная версия в FreeBSD 15.0. Репозиторий |
Пользовательское окружение, собранное из дерева исходных кодов, может быть установлено в корневой каталог клетки с помощью переменной DESTDIR, что является способом запуска пользовательского окружения -STABLE или собранного вручную в клетке. После сборки мира установите его и остальные дистрибутивные файлы в каталог клетки:
# cd /usr/src
# make buildworld
# make installworld DESTDIR=/usr/local/jails/containers/classic
# make distribution DESTDIR=/usr/local/jails/containers/classicmake distribution устанавливает файлы конфигурации по умолчанию в /etc клетки и выполняется только один раз, при заполнении клетки; повторение этого действия во время обновления перезапишет конфигурацию внутри клетки. Чтобы обновить такую клетку из исходников, следуйте той же последовательности, что и для хост-системы: запустите installworld с тем же DESTDIR, объедините файлы конфигурации с помощью etcupdate -D, указав корневой каталог клетки, и удалите устаревшие файлы и библиотеки с помощью make delete-old delete-old-libs, снова с тем же DESTDIR, вместо использования freebsd-update(8). Полную процедуру обновления из исходного кода см. в Обновление FreeBSD из исходного кода.
17.4.3. Клонирование клетки как шаблона
После того как толстая клетка полностью настроена, с установленными пакетами, включёнными службами и локальной конфигурацией, она может служить шаблонным образом: шаблоном, из которого почти мгновенно развёртываются множество идентичных клеток.
В OpenZFS это делается путем создания снимка настроенного набора данных клетки и его клонирования. Это требует, чтобы исходная клетка располагалась в собственном наборе данных, поэтому создайте её с помощью zfs create, а не mkdir, как в классической процедуре клетки выше:
# zfs create -p zroot/jails/containers/classicОстановите клетку перед созданием снимка, чтобы образ был консистентным, затем создайте снимок и клонируйте набор данных один раз для каждой новой клетки:
# service jail stop classic
# zfs snapshot zroot/jails/containers/classic@template
# zfs clone zroot/jails/containers/classic@template zroot/jails/containers/web1На хосте UFS скопируйте дерево каталогов настроенной клетки вместо этого:
# cp -a /usr/local/jails/containers/classic /usr/local/jails/containers/web1Каждый клон требует своей собственной записи в /etc/jail.conf, или в jail.conf.d, с уникальным именем, путем и IP-адресом. Поскольку параметры path и host.hostname в приведенном выше примере выводятся из имени блока с помощью ${name}, отличаются только имя блока и адрес:
web1 {
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
# HOSTNAME/PATH
host.hostname = "${name}";
path = "/usr/local/jails/containers/${name}";
# NETWORK
ip4.addr = 192.168.1.152;
interface = em0;
}Клон шаблонного образа отличается от тонкой клетки (Тонкие клетки). Тонкая клетка продолжает использовать общую базу только для чтения и обслуживается один раз в шаблоне, тогда как каждый клон шаблонного образа представляет собой полную, независимо записываемую копию, которая обновляется и модернизируется отдельно, как описано в Обновление клетки. Клон OpenZFS изначально является эффективной по пространству копией при записи (copy-on-write), которая разделяет блоки со снимком, и сохраняет зависимость от этого исходного снимка, пока zfs promote не разорвёт её. Для полностью независимой копии или для репликации клетки на другой пул или хост используйте zfs send, переданный через конвейер в zfs receive, вместо zfs clone.
17.5. Тонкие клетки (Thin Jails)
Хотя тонкие клетки используют ту же технологию, что и толстые клетки, процедура их создания отличается. Тонкие клетки можно создавать с использованием снимков OpenZFS или шаблонов и NullFS. Использование снимков OpenZFS и шаблонов с NullFS имеет определённые преимущества перед классическими клетками, например, возможность быстрого создания из снимков или обновления нескольких клеток с помощью NullFS.
17.5.1. Создание тонкой клетки с использованием снимков OpenZFS
Благодаря хорошей интеграции между FreeBSD и OpenZFS создание новых тонких клеток с использованием снимков OpenZFS очень просто.
Для создания тонкой клетки с использованием снимков OpenZFS первым шагом является создание дерева каталогов клетки, следуя инструкциям в разделе Настройка дерева каталогов клетки.
Далее создайте шаблон. Шаблоны будут использоваться только для создания новых клеток. По этой причине они создаются в режиме "только для чтения", чтобы клетки создавались на неизменяемой основе.
Для создания набора данных для шаблона выполните следующую команду:
# zfs create -p zroot/jails/templates/15.1-RELEASEЗатем выполните следующую команду для загрузки пользовательской среды:
# fetch https://download.freebsd.org/releases/amd64/amd64/15.1-RELEASE/base.txz -o /usr/local/jails/media/15.1-RELEASE-base.txzПосле завершения загрузки необходимо извлечь содержимое в каталог шаблона, выполнив следующую команду:
# tar -xf /usr/local/jails/media/15.1-RELEASE-base.txz -C /usr/local/jails/templates/15.1-RELEASE --unlinkКогда пользовательская среда записана в каталог шаблонов, необходимо скопировать файлы часового пояса и DNS-сервера в каталог шаблона, выполнив следующую команду:
# cp /etc/resolv.conf /usr/local/jails/templates/15.1-RELEASE/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/15.1-RELEASE/etc/localtimeСледующее, что нужно сделать, — обновиться до последнего уровня исправлений, выполнив следующую команду:
# freebsd-update -b /usr/local/jails/templates/15.1-RELEASE/ fetch installПосле завершения обновления шаблон готов.
Для создания снимка OpenZFS из шаблона выполните следующую команду:
# zfs snapshot zroot/jails/templates/15.1-RELEASE@baseПосле создания снимка OpenZFS можно создавать бесконечное количество клеток с помощью функции клонирования OpenZFS.
Для создания тонкой клетки с именем thinjail выполните следующую команду:
# zfs clone zroot/jails/templates/15.1-RELEASE@base zroot/jails/containers/thinjailПоследним шагом является настройка клетки. Необходимо добавить запись в конфигурационный файл /etc/jail.conf или в jail.conf.d с параметрами клетки.
Пример может выглядеть следующим образом:
thinjail {
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
# HOSTNAME/PATH
host.hostname = "${name}";
path = "/usr/local/jails/containers/${name}";
# NETWORK
ip4 = inherit;
interface = em0;
}Выполните следующую команду для запуска клетки:
# service jail start thinjailДополнительная информация об управлении клетками приведена в разделе Управление клетками.
17.5.2. Создание тонкой клетки с использованием NullFS
Клетка может быть создана с уменьшенным дублированием системных файлов с использованием техники тонкой клетки и NullFS для выборочного совместного использования определённых каталогов из хост-системы в клетке.
Первым шагом является создание набора данных для сохранения шаблона, выполните следующую команду, если используется OpenZFS:
# zfs create -p zroot/jails/templates/15.1-RELEASE-baseИли эту, если используется UFS:
# mkdir /usr/local/jails/templates/15.1-RELEASE-baseЗатем выполните следующую команду для загрузки пользовательской среды:
# fetch https://download.freebsd.org/releases/amd64/amd64/15.1-RELEASE/base.txz -o /usr/local/jails/media/15.1-RELEASE-base.txzПосле завершения загрузки необходимо извлечь содержимое в каталог шаблона, выполнив следующую команду:
# tar -xf /usr/local/jails/media/15.1-RELEASE-base.txz -C /usr/local/jails/templates/15.1-RELEASE-base --unlinkКогда пользовательская среда записана в каталог шаблонов, необходимо скопировать файлы часового пояса и DNS-сервера в каталог шаблона, выполнив следующую команду:
# cp /etc/resolv.conf /usr/local/jails/templates/15.1-RELEASE-base/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/15.1-RELEASE-base/etc/localtimeПосле перемещения файлов в шаблон следующим шагом будет обновление до последнего уровня исправлений с помощью выполнения следующей команды:
# freebsd-update -b /usr/local/jails/templates/15.1-RELEASE-base/ fetch installВ дополнение к базовому шаблону также необходимо создать каталог, где будет располагаться skeleton. Некоторые каталоги будут скопированы из шаблона в skeleton.
Выполните следующую команду, чтобы создать набор данных для skeleton в случае использования OpenZFS:
# zfs create -p zroot/jails/templates/15.1-RELEASE-skeletonИли эту в случае использования UFS:
# mkdir /usr/local/jails/templates/15.1-RELEASE-skeletonЗатем создайте skeleton-каталоги. Skeleton-каталоги будут содержать локальные каталоги для клеток.
Выполните следующие команды для создания каталогов:
# mkdir -p /usr/local/jails/templates/15.1-RELEASE-skeleton/home
# mkdir -p /usr/local/jails/templates/15.1-RELEASE-skeleton/usr
# mv /usr/local/jails/templates/15.1-RELEASE-base/etc /usr/local/jails/templates/15.1-RELEASE-skeleton/etc
# mv /usr/local/jails/templates/15.1-RELEASE-base/usr/local /usr/local/jails/templates/15.1-RELEASE-skeleton/usr/local
# mv /usr/local/jails/templates/15.1-RELEASE-base/tmp /usr/local/jails/templates/15.1-RELEASE-skeleton/tmp
# mv /usr/local/jails/templates/15.1-RELEASE-base/var /usr/local/jails/templates/15.1-RELEASE-skeleton/var
# mv /usr/local/jails/templates/15.1-RELEASE-base/root /usr/local/jails/templates/15.1-RELEASE-skeleton/rootСледующий шаг — создать символьные ссылки на skeleton, выполнив следующие команды:
# cd /usr/local/jails/templates/15.1-RELEASE-base/
# mkdir skeleton
# ln -s skeleton/etc etc
# ln -s skeleton/home home
# ln -s skeleton/root root
# ln -s ../skeleton/usr/local usr/local
# ln -s skeleton/tmp tmp
# ln -s skeleton/var varКогда skeleton готов, необходимо скопировать данные в клетку.
В случае использования OpenZFS, снимки OpenZFS могут быть использованы для простого создания необходимого количества клеток с помощью выполнения следующих команд:
# zfs snapshot zroot/jails/templates/15.1-RELEASE-skeleton@base
# zfs clone zroot/jails/templates/15.1-RELEASE-skeleton@base zroot/jails/containers/thinjailВ случае использования UFS можно использовать программу cp(1), выполнив следующую команду:
# cp -R /usr/local/jails/templates/15.1-RELEASE-skeleton /usr/local/jails/containers/thinjailЗатем создайте каталог, в котором будут смонтированы базовый шаблон и skeleton:
# mkdir -p /usr/local/jails/thinjail-nullfs-baseДобавьте запись о клетке в /etc/jail.conf или файл в jail.conf.d следующим образом:
thinjail {
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
# HOSTNAME/PATH
host.hostname = "${name}";
path = "/usr/local/jails/${name}-nullfs-base";
# NETWORK
ip4.addr = 192.168.1.153;
interface = em0;
# MOUNT
mount.fstab = "/usr/local/jails/${name}-nullfs-base.fstab";
}Затем создайте файл /usr/local/jails/thinjail-nullfs-base.fstab следующего содержания:
/usr/local/jails/templates/15.1-RELEASE-base /usr/local/jails/thinjail-nullfs-base/ nullfs ro 0 0 /usr/local/jails/containers/thinjail /usr/local/jails/thinjail-nullfs-base/skeleton nullfs rw 0 0
Файл fstab управляет тем, как mount_nullfs(8) представляет базовый шаблон и скелет внутри клетки. Базовый шаблон монтируется только для чтения (ro), чтобы каждая клетка NullFS использовала одну неизменяемую копию базовой системы. Скелет каждой клетки монтируется с возможностью чтения и записи (rw), и именно здесь каждая клетка хранит свои собственные доступные для записи каталоги /etc, /var, /usr/local и другие локальные каталоги. Поскольку все клетки используют один и тот же базовый шаблон только для чтения, обновление одного шаблона сразу обновляет все клетки NullFS, в отличие от независимых клонов OpenZFS, каждый из которых необходимо обновлять отдельно.
Выполните следующую команду для запуска клетки:
# service jail start thinjail17.6. Клетки VNET
В клетках FreeBSD VNET используется отдельный сетевой стек, включающий интерфейсы, IP-адреса, таблицы маршрутизации и правила межсетевого экрана.
Первым шагом для создания VNET-клетки является создание bridge(4) с помощью выполнения следующей команды:
# ifconfig bridge createВывод должен быть похож на следующий:
bridge0
Назначение IP-адреса интерфейсу, который является членом моста, устарело. Назначайте адрес хоста самому |
Создав bridge, необходимо подключить его к интерфейсу em0 и включить оба, выполнив следующие команды:
# ifconfig bridge0 addm em0 up
# ifconfig em0 upЧтобы сохранить этот параметр после перезагрузки, добавьте следующие строки в /etc/rc.conf:
defaultrouter="192.168.1.1" cloned_interfaces="bridge0" ifconfig_bridge0="inet 192.168.1.150/24 addm em0 up" ifconfig_em0="up"
Для получения дополнительной информации о мостах см. Сетевые мосты.
Следующий шаг — создать клетку, как указано выше.
Можно использовать как процедуру Классической Клетки (Толстой клетки), так и процедуру Тонких Клеток. Единственное, что изменится — это конфигурация в файле /etc/jail.conf.
В качестве примера для созданной клетки будет использоваться путь /usr/local/jails/containers/vnet.
Вот пример конфигурации для VNET-клетки:
vnet {
# STARTUP/LOGGING
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
devfs_ruleset = 5;
# PATH/HOSTNAME
path = "/usr/local/jails/containers/${name}";
host.hostname = "${name}";
# VNET/VIMAGE
vnet;
vnet.interface = "${epair}b";
# NETWORKS/INTERFACES
$id = "154"; (1)
$ip = "192.168.1.${id}/24";
$gateway = "192.168.1.1";
$bridge = "bridge0"; (2)
$epair = "epair${id}";
# ADD TO bridge INTERFACE
exec.prestart = "/sbin/ifconfig ${epair} create up";
exec.prestart += "/sbin/ifconfig ${epair}a up descr jail:${name}";
exec.prestart += "/sbin/ifconfig ${bridge} addm ${epair}a up";
exec.start += "/sbin/ifconfig ${epair}b ${ip} up";
exec.start += "/sbin/route add default ${gateway}";
exec.start += "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.poststop = "/sbin/ifconfig ${bridge} deletem ${epair}a";
exec.poststop += "/sbin/ifconfig ${epair}a destroy";
}| 1 | Номер, уникальный для каждой клетки, используемый для получения как имени устройства epair (epair${id}), так и последнего октета адреса клетки (192.168.1.${id}); присвойте каждой клетке на мосту различное значение. |
| 2 | Относится к ранее созданному мосту. |
Параметр vnet.interface задает имя интерфейса, который jail(8) перемещает в сетевой стек клетки после ее создания, здесь это сторона epair, относящаяся к клетке, ${epair}b. Этот интерфейс исчезает с хоста, пока клетка работает, и автоматически возвращается хосту при остановке клетки. Физическая сетевая карта или виртуальная функция SR-IOV могут быть переданы клетке таким же образом, обеспечивая ей выделенную сеть без моста или epair.
Строка devfs_ruleset = 5 применяет набор правил devfsrules_jail_vnet из /etc/defaults/devfs.rules, который расширяет стандартный набор правил для клеток, открывая доступ к /dev/pf. Таким образом, клетка VNET может запускать собственный межсетевой экран pf(4) с pf_enable="YES" и приватным pf.conf, независимым от хоста. Смотрите Devfs Rulesets для описания определений наборов правил и Firewalls для информации о самом pf.
17.6.1. Автоматизация сети VNET с помощью jib
Настройка epair и подключение его к мосту вручную в exec.prestart и exec.poststop, как показано выше, становится утомительной при большом количестве клеток. В базовой системе есть вспомогательный скрипт, /usr/share/examples/jails/jib, который выполняет ту же самую настройку автоматически.
Ссылайтесь на него из хуков клетки вместо пяти самодельных строк ifconfig(8):
exec.prestart += "jib addm ${name} em0";
exec.poststop += "jib destroy ${name}";
vnet.interface = "e0b_${name}";jib addm создает epair, чья сторона хоста называется e0a_<name>, а сторона клетки — e0b_<name>, затем присоединяет сторону хоста к мосту, который он создает автоматически, названному в честь интерфейса-члена (для em0 мост называется em0bridge). Укажите эту сторону клетки в vnet.interface. Когда клетка останавливается, jib destroy удаляет epair. Скрипт также предоставляет подкоманду jib show для вывода списка интерфейсов, которыми он управляет.
17.6.2. Сетевые взаимодействия Netgraph VNET с помощью jng
Третий режим работы сети, упомянутый в обзоре Сеть, использует netgraph(4) вместо bridge(4) и epair. В базовой системе поставляется второй вспомогательный скрипт, /usr/share/examples/jails/jng, который создает ng_bridge, подключенный к ng_eiface для каждой клетки:
exec.prestart += "jng bridge ${name} em0";
exec.poststop += "jng shutdown ${name}";
vnet.interface = "ng0_${name}";jng bridge создает узлы netgraph и интерфейс на стороне клетки с именем ng0_<name>, который указывается в vnet.interface; jng shutdown разрушает топологию при остановке клетки. Результат функционально эквивалентен настройке с epair и bridge, но построен на узлах netgraph, а не на bridge(4).
17.6.3. Запуск межсетевого экрана и DHCP внутри клетки VNET
Поскольку devfs_ruleset = 5 открывает доступ к /dev/pf, клетка VNET может запускать собственный межсетевой экран. Включите его внутри клетки точно так же, как на любом хосте, с помощью pf_enable="YES" в /etc/rc.conf клетки и её собственном /etc/pf.conf.
Однако правила набора 5 не открывают доступ к /dev/bpf. Клетка VNET, которая получает свой адрес через DHCP, например, с помощью ifconfig_e0b_myjail="SYNCDHCP" в её /etc/rc.conf, запускает dhclient(8), которому требуется bpf, и поэтому он терпит неудачу при использовании набора правил 5. Следуя рецепту из Devfs Rulesets, определите собственный набор правил в /etc/devfs.rules, который начинается с devfsrules_jail_vnet и дополнительно открывает устройства bpf:
[devfsrules_jail_vnet_dhcp=101] add include $devfsrules_jail_vnet add path 'bpf*' unhide
После выполнения service devfs restart на хосте, укажите клетке на новый набор правил с помощью devfs_ruleset = 101;.
17.7. Клетки Linux
FreeBSD может запускать пользовательские программы Linux внутри клетки, используя Двоичную совместимость с Linux и sysutils/debootstrap. Клетки не имеют собственного ядра. Они работают на ядре хоста. Поэтому необходимо включить Двоичную совместимость с Linux в хост-системе.
Чтобы включить ABI Linux при загрузке, выполните следующую команду:
# sysrc linux_enable="YES"После включения его можно запустить без перезагрузки, выполнив следующую команду:
# service linux startСледующим шагом будет создание клетки, как указано выше, например, в разделе Создание тонкой клетки с использованием снимков OpenZFS, но без выполнения настройки. Клетки FreeBSD Linux требуют особой конфигурации, которая будет подробно описана ниже.
Если на хосте ещё нет файла /etc/jail.conf — например, в системе, где клетки до сих пор создавались только из командной строки, — создайте пустой файл, чтобы service(8) затем мог остановить клетку:
# touch /etc/jail.confСкрипт service(8) jail читает /etc/jail.conf при остановке клетки, поэтому команда остановки завершается ошибкой, если файл не существует. Если /etc/jail.conf уже присутствует из предыдущего раздела, этот шаг не требуется.
Следующая команда jail(8) выполняет необходимую настройку для клетки и запускает её напрямую, без записи в /etc/jail.conf. Флаг -c создаёт новую клетку, а -m изменяет существующую; в сочетании как -cm, jail(8) создаёт клетку, если она ещё не существует, и обновляет её, если она существует:
# jail -cm \
name=ubuntu \
host.hostname="ubuntu.example.com" \
path="/usr/local/jails/containers/ubuntu" \
interface="em0" \
ip4.addr="192.168.1.155" \
exec.start="/bin/sh /etc/rc" \
exec.stop="/bin/sh /etc/rc.shutdown" \
mount.devfs \
devfs_ruleset=4 \
allow.mount \
allow.mount.devfs \
allow.mount.fdescfs \
allow.mount.procfs \
allow.mount.linprocfs \
allow.mount.linsysfs \
allow.mount.tmpfs \
enforce_statfs=1Получите доступ к вновь созданной клетке как root с помощью jexec(8):
# jexec -u root ubuntu shВнутри клетки установите sysutils/debootstrap и используйте его для сборки пользовательского окружения Ubuntu в /compat/ubuntu. sysutils/debootstrap — это инструмент, который собирает пользовательское окружение Linux; после этого он не требуется для входа в клетку. Первый запуск pkg(7) автоматически выполняет его начальную настройку:
# pkg install debootstrap
# debootstrap jammy /compat/ubuntujammy выбирает Ubuntu 22.04 LTS. Можно выбрать более новую LTS, например noble (Ubuntu 24.04), при условии, что она работает в linuxulator.
Когда процесс завершится и на консоли появится сообщение Base system installed successfully, из хост-системы остановите клетку. Так как эта клетка не активирована в /etc/rc.conf и еще не перечислена в /etc/jail.conf, используйте действие service(8) с префиксом one, которое запускает клетки, которые не активированы:
# service jail onestop ubuntuДействия onestart и onestop являются аналогами start и stop для клеток, которые не включены через jail_enable или не перечислены в jail_list.
Затем добавьте запись в /etc/jail.conf для Linux-контейнера:
ubuntu {
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
devfs_ruleset = 4;
# HOSTNAME/PATH
host.hostname = "${name}";
path = "/usr/local/jails/containers/${name}";
# NETWORK
ip4.addr = 192.168.1.155;
interface = em0;
# MOUNT
mount += "devfs $path/compat/ubuntu/dev devfs rw 0 0";
mount += "tmpfs $path/compat/ubuntu/dev/shm tmpfs rw,size=1g,mode=1777 0 0";
mount += "fdescfs $path/compat/ubuntu/dev/fd fdescfs rw,linrdlnk 0 0";
mount += "linprocfs $path/compat/ubuntu/proc linprocfs rw 0 0";
mount += "linsysfs $path/compat/ubuntu/sys linsysfs rw 0 0";
mount += "/tmp $path/compat/ubuntu/tmp nullfs rw 0 0";
mount += "/home $path/compat/ubuntu/home nullfs rw 0 0";
}Клетка также может представлять конкретную идентичность ядра Linux программам, работающим внутри неё. Параметр |
Затем клетку можно запустить как обычно с помощью следующей команды:
# service jail start ubuntuОкружение Ubuntu можно запустить с помощью следующей команды:
# jexec ubuntu chroot /compat/ubuntu /bin/bashДополнительную информацию можно найти в главе Двоичная совместимость с Linux.
17.8. NAT и перенаправление портов для клеток
Клетка, которой присвоен частный адрес — на клонированном интерфейсе lo(4), таком как lo1, на частном мосту или на VNET epair во внутренней сети, — не имеет собственного маршрута в интернет. Хост должен транслировать трафик клетки в маршрутизируемый адрес, а для доступа к службе, работающей внутри такой клетки, извне — перенаправлять входящие соединения на клетку.
Сначала разрешите хосту пересылать пакеты между его интерфейсами. Включите это при загрузке и немедленно с помощью следующих команд:
# sysrc gateway_enable="YES"
# sysctl net.inet.ip.forwarding=1Для IPv6 используйте ipv6_gateway_enable="YES" и net.inet6.ip6.forwarding=1.
Затем настройте трансляцию сетевых адресов на хосте с помощью pf(4). Следующий /etc/pf.conf предоставляет каждой клетке в частной сети 192.168.0.0/24 исходящий доступ через внешний интерфейс хоста em0 и публикует веб-сервер внутри клетки на порту 80 хоста:
ext_if = "em0" # Translate outbound jail traffic to the host address nat on $ext_if from 192.168.0.0/24 to any -> ($ext_if) # Forward inbound web traffic to the jailed server rdr on $ext_if proto tcp to port 80 -> 192.168.0.151
Цель rdr должна быть собственным адресом клетки.
Активируйте и запустите pf(4) с помощью следующей команды:
# sysrc pf_enable="YES"
# service pf startFreeBSD 15.0 добавляет синтаксис в стиле OpenBSD для встроенных |
Для полного рассмотрения pf(4) и ipfw(8), включая полные наборы правил и NAT на основе ipfw(8), см. Межсетевые экраны.
17.9. Сервисные клетки (Service Jails)
Сервисная клетка полностью настраивается через /etc/rc.conf или sysrc(8). Базовые системные сервисы готовы для работы в сервисных клетках. Они содержат строку конфигурации, которая включает сеть или снимает другие ограничения клеток. Базовые системные сервисы, которые не имеет смысла запускать внутри клеток, настроены так, чтобы не запускаться как сервисные клетки, даже если они включены в /etc/rc.conf. Некоторые примеры таких сервисов — это сервисы, которые хотят монтировать или размонтировать что-то в методе start или stop, или только настраивают что-то, например маршрут, межсетевой экран или подобное.
Сторонние службы могут быть или не быть готовы к использованию в сервисных клетках. Чтобы проверить, готова ли служба к работе в сервисной клетке, можно использовать следующую команду:
# grep _svcj_options /path/to/rc.d/servicenameЕсли вывод отсутствует, служба не готова к работе в клетке или не требует дополнительных привилегий, таких как, например, доступ к сети.
Если служба не готова к работе в клетке и требует доступа к сети, её можно подготовить, добавив необходимую конфигурацию в /etc/rc.conf:
# sysrc servicename_svcj_options=net_basicДля всех возможных _svcj_options см. справочную страницу rc.conf(5).
Для включения сервисной клетки для указанной службы необходимо остановить службу и установить переменную servicename_svcj в значение YES. Чтобы поместить syslogd(8) в сервисную клетку, используйте следующую последовательность команд:
# service syslogd stop
# sysrc syslogd_svcj=YES
# service syslogd startЕсли переменная servicename_svcj изменяется, службу необходимо остановить перед внесением изменений. Если она не будет остановлена, rc-фреймворк не определит корректное состояние службы и не сможет выполнить запрошенное действие.
Сервисные клетки управляются только через rc.conf(5)/sysrc(8) и команду service(8). Утилиты для работы с клетками, такие как jls(8), описанные в разделе Управление клетками, могут использоваться для проверки их работы, но команда jail(8) не предназначена для управления ими.
17.10. Управление клетками
После создания клетки можно выполнить ряд операций, таких как запуск, перезагрузка или удаление клетки, установка программного обеспечения в неё и т.д. В этом разделе описаны различные действия, которые можно выполнять с клетками с хоста.
17.10.1. Список работающих клеток
Для вывода списка клеток, запущенных в хост-системе, можно использовать команду jls(8):
# jlsВывод должен быть похож на следующий:
JID IP Address Hostname Path
1 192.168.1.151 classic /usr/local/jails/containers/classicjls(8) поддерживает аргумент --libxo, который через библиотеку libxo(3) позволяет отображать данные в других форматах, таких как JSON, HTML и т.д.
Например, выполните следующую команду для получения вывода в формате JSON:
# jls --libxo=jsonВывод должен быть похож на следующий:
{"__version": "2", "jail-information": {"jail": [{"jid":1,"ipv4":"192.168.1.151","hostname":"classic","path":"/usr/local/jails/containers/classic"}]}}Стандартный вывод является лишь малой частью того, что может сообщить jls(8). Добавьте флаг -v для подробной многострочной сводки по каждой клетке, включающей её состояние и назначенный идентификатор набора процессоров (cpuset ID):
# jls -vИспользуйте -h для вывода строки заголовка с названиями полей над значениями запрашиваемых параметров:
# jls -h jid name pathЧтобы запросить конкретные параметры одной клетки, укажите её с помощью -j и перечислите параметры для вывода:
# jls -j classic path host.hostname ip4.addrВывод должен быть похож на следующий:
/usr/local/jails/containers/classic classic 192.168.1.151
Добавьте -d, чтобы включить клетки, которые завершают работу и в противном случае скрыты, пока находятся в состоянии завершения:
# jls -d17.10.2. Запуск, перезапуск и остановка клетки
service(8) используется для запуска, перезагрузки или остановки клетки на хосте.
Например, чтобы запустить клетку, выполните следующую команду:
# service jail start jailnameИзмените аргумент start на restart или stop, чтобы выполнить другие действия с клеткой.
Остановка клетки — это не просто завершение процессов внутри неё. Когда клетка останавливается, jail(8) сначала выполняет команды из её параметра exec.stop — обычно /bin/sh /etc/rc.shutdown — внутри клетки, чтобы её службы корректно завершились. Затем он отправляет SIGTERM всем процессам, всё ещё работающим в клетке, и ждёт до stop.timeout секунд (по умолчанию 10) их завершения. По истечении этого времени клетка удаляется, что завершает оставшиеся процессы сигналом SIGKILL. Если stop.timeout установлен в ноль, SIGTERM не отправляется, и клетка удаляется немедленно. Именно поэтому клетка с медленно останавливающимся демоном может казаться зависшей на десять секунд при остановке; увеличьте stop.timeout в /etc/jail.conf для клетки, в которой работает база данных или другая служба, требующая больше времени для корректного завершения.
17.10.3. Удаление клетки
Удаление клетки, это не просто остановка клетки с помощью service(8) и удаление каталога клетки и записи в /etc/jail.conf.
FreeBSD очень серьезно относится к безопасности системы. По этой причине существуют определённые файлы, которые не может удалить даже пользователь root. Эта функциональность называется Флаги Файлов. В клетках, чьи файлы находятся на файловой системе UFS, эти флаги должны быть очищены до удаление каталога клетки.
Первым шагом является остановка нужной клетки с помощью выполнения следующей команды:
# service jail stop classicВторой шаг — удалить эти флаги с помощью chflags(1), выполнив следующую команду, где classic — имя удаляемой клетки:
# chflags -R 0 /usr/local/jails/containers/classicТретий шаг — удалить каталог, в котором находилась клетка:
# rm -rf /usr/local/jails/containers/classicДва шага выше относятся к клетке, хранящейся в файловой системе UFS. Клетка, поддерживаемая собственным набором данных ZFS — как созданная в Настройка дерева каталогов клетки — удаляется вместо этого путем уничтожения набора данных. Уничтожение набора данных не блокируется файловыми флагами, поэтому шаг с chflags(1) в этом случае не требуется:
# service jail stop classic
# zfs destroy zroot/jails/containers/classicДобавьте -r, чтобы также уничтожить любые снимки, которые хранит набор данных.
Тонкая клетка на ZFS, созданная клонированием снимка шаблона (см. Тонкие клетки), зависит от этого снимка. Пока существует любой клон, zfs(8) отказывается уничтожать снимок шаблона и выводит список зависимых клонов. Чтобы удалить шаблон, сначала уничтожьте каждую клетку, клонированную из него, или выполните |
Наконец, в любом случае удалите запись клетки в /etc/jail.conf или в /etc/jail.conf.d. Для тонкой клетки NullFS также удалите её файл .fstab и её теперь пустой каталог точки монтирования.
17.10.4. Работа с пакетами в клетке
Утилита pkg(8) поддерживает аргумент -j для управления пакетами, установленными внутри клетки.
Например, чтобы установить пакет www/nginx-lite в клетке, можно выполнить следующую команду с хоста:
# pkg -j classic install nginx-liteДля получения дополнительной информации о работе с пакетами в FreeBSD см. Установка приложений: Пакеты и порты.
17.10.5. Управление службами в клетке с хост-системы
Службы внутри клетки можно включать и контролировать с хост-системы, не заходя сначала в клетку через jexec(8). Как service(8), так и sysrc(8) принимают аргумент -j, который указывает целевую клетку по ID или имени и работает с конфигурацией rc(8) этой клетки.
Продолжая пример с пакетами выше, включите и запустите nginx в клетке classic непосредственно с хост-системы:
# sysrc -j classic nginx_enable=YES
# service -j classic nginx startЭти команды имеют тот же эффект, что и запуск sysrc(8) и service(8) через jexec(8), но они сохраняют единообразие администрирования и написания сценариев на стороне хост-системы с системой без клеток.
17.10.6. Доступ к клетке
Как уже упоминалось выше, оптимальным является управление клетками из хост-системы, однако в клетку можно войти с помощью jexec(8).
В клетку можно войти, выполнив jexec(8) с хоста:
# jexec -u root jailnameФлаг -u выбирает пользователя, от имени которого выполняется команда, разрешая имя через базу данных паролей хост-системы. Чтобы разрешить пользователя через собственную базу данных паролей клетки, используйте -U. Если команда не задана, как в данном случае, jexec(8) запускает оболочку входа этого пользователя внутри клетки. Добавьте -l, чтобы запустить её в чистой среде входа, сохраняющей только HOME, SHELL, TERM и USER, сбрасывающей PATH на /bin:/usr/bin и ведущей себя как новый вход; -d задаёт рабочую директорию, по умолчанию это корень клетки.
При входе в клетку будет отображено сообщение, настроенное в motd(5).
17.10.7. Выполнение команд в клетке
Для выполнения команды в клетке из хост-системы можно использовать jexec(8).
Например, чтобы остановить службу, работающую внутри клетки, будет выполнена команда:
# jexec -l jailname service nginx stop17.10.8. Просмотр процессов и сокетов в клетках с хост-системы
С хост-системы процессы и сокеты каждой клетки видны и могут фильтроваться по клетке.
ps(1) принимает -J для ограничения своего вывода одной клеткой, заданной по JID или имени:
# ps -J classicВывод должен быть похож на следующий, где J в столбце STAT отмечает процесс, запущенный в клетке:
PID TT STAT TIME COMMAND 2841 - IsJ 0:00.02 /usr/sbin/syslogd -ss 2903 - IsJ 0:00.00 nginx: master process /usr/local/sbin/nginx
Используйте ps -J 0, чтобы показать только процессы самой хост-системы. Ключевые слова jail и jid также можно добавить в формат вывода -o, чтобы показать, к какой клетке относится каждый процесс. Например, чтобы вывести список всех процессов на хост-системе вместе с их клеткой:
# ps ax -o pid,jail,commandtop(1) принимает -J для фильтрации своего живого отображения по одной клетке, что подразумевает -j и добавляет столбец JID:
# top -J classicsockstat(1) выводит список сокетов, принадлежащих клетке, с помощью -j, что является естественным способом проверить, какие порты демоны клетки фактически привязали после запуска в ней службы:
# sockstat -4 -6 -l -j classicИзнутри клетки картина обратная: процесс, заключенный в клетку, видит только процессы и сокеты своей собственной клетки и никогда не видит процессы или сокеты хоста или других клеток.
17.10.9. Управление клетками напрямую с помощью утилиты jail
Представленная выше обёртка service(8) — это обычный способ запуска клеток при загрузке, но jail(8) также может создавать, изменять и удалять клетки напрямую, что полезно для написания скриптов и тестирования конфигурации без фреймворка rc.
Создайте настроенную клетку по имени:
# jail -c classicУдалите работающую клетку; это также удалит все дочерние клетки, которые она создала, и завершит процессы внутри неё:
# jail -r classicФлаг -m изменяет параметры уже запущенной клетки без её перезапуска. Например, чтобы добавить второй IPv4-адрес к запущенной клетке:
# jail -m name=classic ip4.addr+=192.168.250.71jail(8) отмечает, что «некоторые параметры нельзя изменить в работающей клетке»; на практике это включает path и vnet, для изменения которых требуется перезапуск клетки.
Наконец, -e отображает все настроенные не-шаблонные клетки и их параметры без создания, изменения или удаления чего-либо, что удобно для проверки файла конфигурации. В качестве аргумента она принимает строку, используемую для разделения параметров:
# jail -e ,17.10.10. Резервное копирование и перенос клетки
Клетка в значительной степени самодостаточна, поэтому её резервное копирование или перенос на другой хост в основном сводится к копированию её файлов и её конфигурации.
Остановите клетку сначала для получения консистентной копии; клетку на основе ZFS можно вместо этого сделать снимок во время её работы. Для клетки на собственном наборе данных ZFS выполните рекурсивный снимок и передайте его на целевой хост:
# service jail stop classic
# zfs snapshot -r zroot/jails/containers/classic@migrate
# zfs send -R zroot/jails/containers/classic@migrate | ssh newhost zfs receive zroot/jails/containers/classicПолная механика zfs-send(8) и zfs-receive(8), включая инкрементальные передачи, описана в Репликация.
Для клетки на файловой системе UFS используйте tar(1) с опцией -p, чтобы сохранить владельца, права доступа и флаги файлов:
# tar -cpf classic.tar -C /usr/local/jails/containers classicИзвлеките архив как root на целевой системе с помощью tar -xpf, чтобы сохранились флаги. dump(8) и restore(8) являются альтернативой, когда клетка занимает выделенную файловую систему UFS; они работают с целыми файловыми системами, поэтому не применимы к структуре, используемой в этой главе, где все клетки являются каталогами в одной общей файловой системе.
Наконец, скопируйте блок строк, относящихся к клетке, из /etc/jail.conf — или его файл в /etc/jail.conf.d — на новый хост, настройте любые параметры, специфичные для хоста, такие как interface, ip4.addr или мост, используемый клеткой VNET, и запустите клетку там.
Целевая хост-система не должна запускать более старую версию FreeBSD, чем пользовательское окружение клетки, следуя тому же правилу, что клетка никогда не может запускать более новую версию, чем её хост-система. Тонкая клетка на NullFS не является автономной: её шаблон и скелет также должны существовать на целевой хост-системе, поэтому перенесите и их, или сначала преобразуйте клетку в толстую копию. Любые правила rctl(8), хранящиеся в /etc/rctl.conf, должны быть перенесены отдельно. |
17.11. Администрирование изнутри клетки
Большая часть администрирования клеток выполняется с хост-системы, но некоторые задачи выполняются изнутри самой клетки, и скрипт, запущенный внутри клетки, иногда должен знать, что он находится в клетке. В этом разделе описывается, что администратор видит и может делать изнутри клетки.
Процесс может определить, находится ли он внутри клетки, прочитав sysctl security.jail.jailed, который равен 1 внутри клетки и 0 на хост-системе:
# sysctl security.jail.jailed
security.jail.jailed: 1Внутри клетки окружение намеренно ограничено:
Вид на хост-систему скрыт. Процесс, находящийся в клетке, видит только процессы, сокеты и файловые системы своей собственной клетки, но никогда не видит процессы, сокеты и файловые системы хост-системы или других клеток.
Состояние ядра в значительной степени доступно только для чтения. Настраиваемые параметры ядра не могут быть записаны изнутри клетки, kldload(8) и kldunload(8) не разрешены, а dmesg(8) и буфер сообщений ядра недоступны, если не установлен параметр
allow.read_msgbuf.Привилегированные операции, которые пересекали бы границу клетки, запрещены, если только хост-система явно не разрешает их. Создание raw-сокетов — как того требуют ping(8) и traceroute(8) — требует
allow.raw_sockets(см. описание параметра в разделе Файлы конфигурации клеток), монтирование файловых систем требуетallow.mountи его дочерних параметров для конкретных файловых систем, а chflags(1) по умолчанию отключен (см. Обновление клеток).
Горстка переменных sysctl, относящихся к каждой клетке, может быть изменена изнутри клетки без влияния на хост-систему, включая kern.hostname, kern.domainname, kern.hostid, kern.hostuuid, kern.securelevel и security.bsd.suser_enabled. Текущий набор доступных параметров клетки можно вывести с помощью sysctl(8):
# sysctl -d security.jail.paramУправление собственными службами клетки изнутри работает точно так же, как и в системе вне клетки: service(8) и sysrc(8) работают с собственной конфигурацией rc(8) клетки. Это внутриклеточный аналог показанных выше service -j и sysrc -j из хост-системы.
17.12. Обновление клетки
Обновление клеток FreeBSD гарантирует, что изолированные среды остаются безопасными, актуальными и соответствуют последним функциям и улучшениям, доступным в экосистеме FreeBSD.
Правильный инструмент зависит от того, как была установлена пользовательская среда клетки. Клетки, установленные из набора дистрибутивов (файл base.txz, извлечённый в разделах создания, или созданный с помощью bsdinstall(8)), обновляются с хоста с помощью freebsd-update(8) через его флаг -j, как на FreeBSD 14.x, так и на 15.x. Клетки, установленные из базовых пакетов, доступных с FreeBSD 15.0, обновляются с помощью pkg(8) вместо этого; freebsd-update(8) к ним не применяется. Клетки, собранные из исходного кода, обновляются с помощью процедуры для исходного кода (make installworld и make distribution). Никогда не смешивайте эти механизмы в одной клетке.
Поддержка наборов дистрибутивов планируется к удалению в FreeBSD 16, но будет продолжена, вместе с freebsd-update(8), на протяжении всего срока жизни стабильной ветки FreeBSD 15. Базовые пакеты предлагаются как технологическая превью в FreeBSD 15.0 и, как ожидается, станут стандартным методом в будущих выпусках, поэтому pkgbase — это перспективный путь. |
В OpenZFS выполните снимок набора данных клетки перед обновлением, чтобы неудачное обновление можно было мгновенно отменить: Если обновление не удалось, остановите клетку и выполните |
17.12.1. Обновление классической клетки или тонкой клетки с использованием снимков OpenZFS
Клетки должны обновляться их операционной системы хоста. В FreeBSD по умолчанию запрещено использование chflags(1) в клетке. Это предотвращает обновление некоторых файлов, поэтому обновление изнутри клетки завершится ошибкой.
Для обновления клетки до последнего патч-релиза версии FreeBSD, под которой он работает, выполните следующие команды на хосте:
# freebsd-update -j classic fetch install
# service jail restart classicДля обновления клетки до новой основной или промежуточной версии сначала обновите хост-систему, как описано в Выполнение обновлений основной и промежуточной версий. После обновления и перезагрузки хоста можно обновить клетку.
В случае обновления с одной версии на другую проще создать новую клетку, чем выполнять полное обновление. |
Например, для обновления с классической клетки до 15.1-RELEASE выполните следующие команды на хосте:
# freebsd-update -j classic -r 15.1-RELEASE upgrade
# freebsd-update -j classic install
# service jail restart classic
# freebsd-update -j classic install
# service jail restart classicШаг |
Затем, если это было обновление основной версии, переустановите все установленные пакеты и перезапустите клетку снова. Это необходимо, потому что версия ABI изменяется при обновлении между основными версиями FreeBSD.
С хоста:
# pkg -j classic upgrade -f
# service jail restart classic17.12.2. Обновление тонкой клетки OpenZFS
Тонкие клетки, созданные в Создание тонкой клетки с помощью снимков OpenZFS, являются клонами OpenZFS снимка шаблона, но после создания клон независим от этого шаблона. Обновление шаблона не обновляет клетки, которые уже были клонированы из него, а обновление клона не обновляет шаблон. Поэтому существует два способа поддерживать эти клетки в актуальном состоянии.
Первый вариант — обновить каждый клон на месте с помощью freebsd-update(8), точно так же, как и для классической клетки, как описано в Обновление классической клетки или тонкой клетки с использованием снимков OpenZFS. Это самый простой подход для нескольких клеток, но каждый пропатченный клон отклоняется от шаблонного снимка: изменённые блоки дублируются для каждой клетки, что сокращает экономию места, а крупное обновление переписывает так много пользовательского окружения, что большая часть совместного использования теряется.
Второй вариант сохраняет совместное использование, обновляя шаблон и повторно клонируя его. Обновите шаблон до последнего уровня исправлений на хосте:
# freebsd-update -b /usr/local/jails/templates/15.1-RELEASE/ fetch installfreebsd-update(8) с параметром |
Затем создайте новый снимок и клонируйте будущие клетки из него:
# zfs snapshot zroot/jails/templates/15.1-RELEASE@base-p2
# zfs clone zroot/jails/templates/15.1-RELEASE@base-p2 zroot/jails/containers/newjailСуществующие клоны сохраняют базу, из которой они были созданы, до тех пор, пока они не будут пересозданы из нового снимка. Для обновления основной или дополнительной версии создайте новый шаблонный набор данных для нового выпуска, следуя разделу Создание тонкой клетки с помощью снимков OpenZFS, вместо обновления существующего шаблона на месте, и клонируйте новые клетки из его снимка @base.
Храните данные приложений и конфигурацию каждой клетки на отдельных наборах данных или в локальном хранилище клетки, чтобы повторное создание клетки из обновлённого снимка шаблона было дешёвым и предпочтительным по сравнению с отдельным обновлением каждого клона. |
17.12.3. Обновление тонкой клетки с использованием NullFS
Поскольку тонкие клетки, использующие NullFS, разделяют большинство системных каталогов, их очень легко обновлять. Достаточно обновить шаблон. Это позволяет обновлять несколько клеток одновременно.
Для обновления шаблона до последнего патч-релиза версии FreeBSD, на которой он работает, выполните следующие команды на хосте:
# freebsd-update -b /usr/local/jails/templates/15.1-RELEASE-base/ fetch install
# service jail restartДля обновления шаблона до новой основной или промежуточной версии сначала обновите хост-систему, как описано в Выполнение обновлений основной и промежуточной версий. После обновления и перезагрузки хост-системы можно обновить шаблон.
Поскольку хост-система была обновлёна первой, freebsd-update(8) с -b в противном случае обнаружил бы новый выпуск хост-системы, а не более старый выпуск шаблона: -b считывает текущую версию из uname -r хост-системы, в отличие от -j, который определяет собственную пользовательскую среду клетки. Передайте --currently-running <release-шаблона>, чтобы шаблон был обновлён с его фактического выпуска. Следующий пример обновляет шаблон, работающий на 14.2-RELEASE, до 14.3-RELEASE; подставьте применимые выпуски:
# freebsd-update -b /usr/local/jails/templates/14.2-RELEASE-base/ --currently-running 14.2-RELEASE -r 14.3-RELEASE upgrade
# freebsd-update -b /usr/local/jails/templates/14.2-RELEASE-base/ install
# service jail restart
# freebsd-update -b /usr/local/jails/templates/14.2-RELEASE-base/ install
# service jail restart17.12.4. Обновление клеток с pkgbase
Клетки, установленные из базовых пакетов, доступных с FreeBSD 15.0, обновляются с помощью pkg(8) через репозиторий FreeBSD-base, а не с помощью freebsd-update(8).
Репозиторий FreeBSD-base определён в /etc/pkg/FreeBSD.conf, но по умолчанию отключён в FreeBSD 15.0, поэтому включите его перед обновлением.
С хост-системы укажите pkg(8) на корневой каталог клетки с помощью -r (--rootdir):
# pkg -r /usr/local/jails/containers/pkgjail update
# pkg -r /usr/local/jails/containers/pkgjail upgrade
# service jail restart pkgjailТот же самый апгрейд можно выполнить изнутри клетки с помощью jexec(8) и обычной команды pkg upgrade:
# jexec -l pkgjail pkg upgrade
# service jail restart pkgjailpkg(8) выполняет трехстороннее слияние размеченных конфигурационных файлов в /etc. Когда слияние не может быть завершено автоматически, он оставляет новую версию как <file>.pkgnew, а когда он забирает файл, который ранее не был упакован, он сохраняет старую копию как <file>.pkgsave. Проверьте /etc после обновления и вручную согласуйте любые такие файлы. Не запускайте etcupdate(8) в системе pkgbase; pkg(8) сам обрабатывает слияние конфигураций. Смотрите Обновление и модернизация FreeBSD для описания рабочего процесса с базовыми пакетами на стороне хоста.
17.13. Ограничения ресурсов клетки
Управление ресурсами хост-системы, которые использует клетка — это задача, которую должен учитывать системный администратор.
Используйте rctl(8) для управления ресурсами хост-системы, которые клетка может использовать.
Настройка |
Синтаксис для ограничения ресурсов клетки выглядит следующим образом:
rctl -a jail:<jailname>:resource:action=amount[/per]
Необязательный компонент per не является процентным соотношением; это учетная единица, к которой применяется ограничение: одна из process, user, loginclass или jail. Например, deny=2G/jail ограничивает сумму для всей клетки, тогда как deny=2G/process применяет то же значение к каждому процессу по отдельности. Процентное соотношение имеет смысл только для ресурса pcpu, количество которого выражается в процентах от одного ядра процессора.
Например, чтобы ограничить максимальный объём оперативной памяти, доступной для клетки, выполните следующую команду:
# rctl -a jail:classic:memoryuse:deny=2GЧтобы ограничение сохранялось после перезагрузки хост-системы, необходимо добавить правило в файл /etc/rctl.conf следующим образом:
jail:classic:memoryuse:deny=2G/jail
rctl(8) может ограничивать гораздо больше, чем память. Ресурсы, наиболее значимые для клетки, включают pcpu (процент одного ядра ЦП), maxproc (количество процессов), openfiles (открытые файловые дескрипторы), vmemoryuse (адресное пространство) и swapuse (пространство подкачки). Каждый из них настраивается одинаково:
# rctl -a jail:classic:pcpu:deny=80
# rctl -a jail:classic:maxproc:deny=1000
# rctl -a jail:classic:openfiles:deny=5000
# rctl -a jail:classic:vmemoryuse:deny=4GПропускная способность диска ограничивается параметрами readbps и writebps, но эти ресурсы не поддерживают действие deny; вместо этого объединяйте их с throttle:
# rctl -a jail:classic:writebps:throttle=1mДействие после ресурса определяет, что происходит при достижении лимита: deny блокирует операцию, log записывает её в системный журнал, а devctl отправляет уведомление через devd(8).
Сообщите о текущем использовании ресурсов клетки с помощью флага -u, добавив -h для единиц, удобных для чтения человеком:
# rctl -hu jail:classicПеречислите правила, которые применяются к клетке:
# rctl jail:classicУдалите каждое правило, которое соответствует клетке, с помощью -r:
# rctl -r jail:classicДополнительная информация об ограничениях ресурсов доступна в главе о безопасности в разделе Ограничения ресурсов.
17.13.1. Привязка CPU с помощью cpuset
rctl(8) с ограничением pcpu определяет, сколько времени ЦП может потреблять клетка, но она не привязывает клетку к конкретным ядрам; cpuset(1) вместо этого назначает конкретные ядра.
Ограничить работающую клетку набором CPU по её имени или JID:
# cpuset -l 0-3 -j classicЗапросить ядра, которые клетка в настоящее время может использовать, с помощью -g:
# cpuset -g -j classicНазначенный набор также отображается в столбце cpuset команды jls -v. В файле jail.conf нет параметра для привязки к процессору, поэтому закрепите клетку при запуске, выполнив cpuset(1) из хука exec.created или exec.poststart, оба из которых выполняются в среде хоста:
exec.poststart = "cpuset -l 0-3 -j classic";
17.13.2. Ограничение дискового пространства
rctl(8) не имеет ресурса для файлового пространства. Когда каждая клетка находится в собственном наборе данных ZFS, ограничьте и гарантируйте использование дискового пространства с помощью квот и резервирований ZFS вместо этого:
# zfs set quota=20G zroot/jails/containers/classic
# zfs set reservation=5G zroot/jails/containers/classicДля этого требуется, чтобы клетка была собственным набором данных. Созданные ранее тонкие клетки ZFS уже таковыми являются, но процедура Классической Клетки создает каталог клетки с помощью mkdir внутри общего набора данных containers, поэтому сначала создайте его с помощью zfs create, чтобы эти команды применялись. См. Настройка дерева каталогов клетки для структуры наборов данных и zfs-set(8) для свойств quota и reservation.
17.14. Дополнительные параметры клетки
jail(8) предоставляет гораздо больше параметров, чем используется в примерах из этой главы. Клетка является сильной границей изоляции, но не абсолютной. Каждое послабление allow.* обменивает изоляцию на возможности и приближает привилегированных пользователей клетки на шаг ближе к привилегиям root на хост-системе. Предоставляйте клетке только те разрешения, которые действительно необходимы для выполняемой в ней рабочей нагрузки, а всё остальное оставляйте в более ограничительном режиме по умолчанию. Полный список приведён в jail(8) и jail.conf(5); параметры ниже — это те, к которым администраторы обращаются чаще всего.
17.14.1. Разрешения allow.*
Параметры allow.* являются логическими значениями, которые предоставляют отдельные привилегии клетке. Согласно jail(8), "За исключением allow.set_hostname и allow.reserved_ports, эти логические параметры по умолчанию выключены", поэтому клетка запускается в заблокированном состоянии, и каждая возможность должна быть предоставлена явно.
| Параметр | По умолчанию | Эффект |
|---|---|---|
| On | Клетка может изменить собственное имя хоста. |
| On |
|
| Off | Включает «сырые» (raw) сокеты, чтобы ping(8) и traceroute(8) работали внутри клетки. |
| Off |
|
| Off | Клетка может монтировать и размонтировать файловые системы, вместе с дочерними опциями |
| Off | Клетка может администрировать квоты файловой системы. |
| Off | Процессы в клетках могут читать буфер сообщений ядра с помощью dmesg(8). |
| Off | Разрешает семейства адресов сокетов, отличные от IPv4, IPv6, локальных и маршрутных. |
| Off | Процессы в клетках могут блокировать физическую память с помощью mlock(2). |
| Off | Непривилегированные пользователи могут использовать средства отладки для своих собственных процессов. |
| Off | Клетка может использовать гипервизор vmm(4) для запуска гостевых систем bhyve(8). |
| Off | Клетка может запускать NFS-сервер. |
Взвесьте каждое послабление относительно того, что оно открывает: allow.raw_sockets позволяет процессам в клетке подделывать пакеты, allow.chflags позволяет root в клетке снимать флаги неизменяемости и только для добавления, на которые полагается хост-система, а allow.mount открывает пространство имён файловой системы.
Запуск NFS-сервера внутри клетки, отмеченный в примечаниях к выпуску FreeBSD 14.0, требует установки параметра allow.nfsd, VNET-клетки, корневой каталог которой сам является точкой монтирования файловой системы, а также параметра enforce_statfs, не установленного в значение 0.
17.14.2. IPC System V (межпроцессное взаимодействие)
Базы данных и другое программное обеспечение, которое полагается на разделяемую память System V, семафоры и очереди сообщений, управляются по модулям с помощью параметров sysvmsg, sysvsem и sysvshm. Каждый из них принимает одно из трёх значений: inherit делает все объекты IPC узла видимыми для клетки, new предоставляет клетке собственное частное пространство имён ключей, а disable приводит к сбою этих системных вызовов.
Для классического случая запуска PostgreSQL в клетке, выбор new является правильным, предоставляя базе данных собственное пространство имён разделяемой памяти, не раскрывая пространство хост-системы:
sysvmsg = new; sysvsem = new; sysvshm = new;
Устаревший параметр allow.sysvipc больше не используется. Он эквивалентен установке всех трех параметров модуля в значение inherit, что разделяет общесистемное пространство имен IPC с клеткой, поэтому предпочтительнее использовать указанные выше параметры для каждого модуля.
17.14.3. Монтирование файловых систем
allow.mount позволяет клетке монтировать файловые системы, а семейство дочерних параметров выбирает, какие именно типы: allow.mount.devfs, allow.mount.fdescfs, allow.mount.fusefs, allow.mount.nullfs, allow.mount.procfs, allow.mount.linprocfs, allow.mount.linsysfs, allow.mount.tmpfs и allow.mount.zfs. Согласно jail(8), каждый дочерний параметр «действует только вместе с allow.mount и только когда enforce_statfs установлен в значение ниже 2». Удобные параметры mount.devfs, mount.fdescfs и mount.procfs автоматически монтируют соответствующие файловые системы для клетки, а mount.fstab указывает на файл fstab с дополнительными точками монтирования.
Параметр enforce_statfs управляет как тем, какие точки монтирования может видеть клетка, так и, согласно приведенному выше правилу, тем, действуют ли разрешения allow.mount.*. Он принимает три значения:
| Значение | Точки монтирования, видимые клетке |
|---|---|
| Все точки монтирования на хост-системе, без каких-либо ограничений. |
| Видны только точки монтирования ниже корневого каталога клетки. |
| Видна только единственная точка монтирования, где расположен корневой каталог клетки. |
Поскольку для прав allow.mount.* требуется значение ниже 2, клетка, которой необходимо монтировать собственные файловые системы, обычно настраивается с параметром enforce_statfs = 1.
17.14.4. Уровень безопасности (securelevel) для каждой клетки
Параметр securelevel устанавливает значение kern.securelevel для клетки и повышает уровень защиты ядра от изменений флагов и устройств внутри клетки. Согласно jail(8), «клетка никогда не имеет более низкого уровня securelevel, чем её родительская система, но, установив этот параметр, она может иметь более высокий». Таким образом, клетка, обращённая к сети, может работать при ужесточённом securelevel = 3, в то время как хост-система остаётся на уровне по умолчанию.
17.14.5. Иерархичские клетки (Hierarchical Jails)
Клетка сама может создавать дочерние клетки, именно так строятся вложенные или иерархические структуры клеток. Параметр children.max задаёт, сколько дочерних клеток может создать клетка; по умолчанию он равен 0, что означает отсутствие разрешения на создание дочерних клеток, а доступный только для чтения параметр children.cur сообщает, сколько их существует в данный момент. Дочерняя клетка никогда не может превысить привилегии своего родителя: согласно jail(8), «Процессы, находящиеся в клетке, не имеют права предоставлять большие полномочия, чем те, которые даны им самим». Это делает возможным запуск менеджера клеток внутри клетки.
17.14.6. Пустые и постоянные клетки
По умолчанию клетка существует только пока в ней есть запущенные процессы; когда её последний процесс завершается, клетка исчезает. Установка параметра persist, по словам jail(8), «позволяет клетке существовать без каких-либо процессов». Именно это поддерживает клетку в живых после её создания пустой и до того, как в неё будет что-либо помещено, а также закрепляет VNET-клетку, которая хранит только сетевое состояние. Клетка может быть создана пустой и поддерживаться в живых для экспериментов:
# jail -c name=test path=/rescue persistСбросьте флаг с помощью nopersist, чтобы клетка могла быть удалена после того, как снова станет неактивной.
17.14.7. Представление другого выпуска ОС
Пользовательское окружение клетки может быть старше, чем ядро хост-системы, но инструменты внутри нее все равно читают версию хост-системы через uname(1), если не указано иное. Параметр osrelease задает строку, сообщаемую через kern.osrelease и uname -r клетки, а osreldate задает число, сообщаемое через kern.osreldate и uname -K. Установка их таким образом, чтобы более старое пользовательское окружение сообщало о собственной версии, обеспечивает корректную работу uname(1), потребителей sysctl(8) и инструментов сборки, определяющих версию, включая freebsd-update(8), запускаемый внутри клетки. Управление пакетами не затрагивается ни в ту, ни в другую сторону, потому что pkg(8) получает свой ABI из ELF-заметок собственных бинарных файлов клетки, а не из uname(1). Это дополняет правило, согласно которому пользовательское окружение клетки никогда не может быть новее, чем ядро хоста; см. Обновление клеток.
17.15. Клетки и ZFS
Клетка может получить контроль над одним или несколькими наборами данных ZFS, позволяя привилегированному пользователю внутри клетки создавать, снимать снимки, клонировать и откатывать дочерние наборы данных без участия администратора хост-системы. Это рекомендуемый способ предоставить клетке собственное записываемое хранилище с поддержкой снимков.
Хост-система сохраняет право собственности на набор данных и делегирует клетке только управление делегированным деревом и его потомками. Свойство jailed, подкоманда zfs jail и взаимодействие между ними описаны в ZFS и клетки.
17.15.1. Ручное делегирование набора данных
Этот метод работает на всех поддерживаемых выпусках FreeBSD.
На хост-системе создайте набор данных для делегирования и пометьте его как клетку:
# zfs create zroot/jails/data
# zfs set jailed=on zroot/jails/dataУстановка свойства jailed сообщает ZFS, что набор данных будет управляться изнутри клетки, поэтому хост-система автоматически перестаёт его монтировать.
Далее, разрешите клетке монтировать файловые системы ZFS и присоединять набор данных при создании клетки. Добавьте следующее в раздел клетки в /etc/jail.conf:
allow.mount;
allow.mount.zfs;
enforce_statfs = 1;
exec.created += "zfs jail ${name} zroot/jails/data";Права allow.mount.zfs действуют только вместе с allow.mount и значением enforce_statfs ниже 2; см. More Jail Options для прав на монтирование и их взаимодействия с enforce_statfs. Поскольку делегированный набор данных отсоединяется при остановке клетки, хук exec.created повторно присоединяет его при каждом запуске, где ${name} расширяется до имени клетки. То же присоединение можно выполнить к уже запущенной клетке с помощью команды zfs jail <jid|name> zroot/jails/data.
Клетке требуется доступ к /dev/zfs. Стандартный набор правил devfs для клеток ( |
Внутри клетки смонтируйте делегированные наборы данных и управляйте ими как любыми другими:
# zfs mount -a
# zfs create zroot/jails/data/work
# zfs snapshot zroot/jails/data/work@mondayroot-пользователь в клетке может создавать, делать снимки, клонировать и откатывать наборы данных в делегированном дереве, но свойство quota делегированного набора данных может быть установлено только с хоста-системы.
17.15.2. Автоматическое подключение наборов данных
Параметр |
Начиная с FreeBSD 15.0, jail(8) может самостоятельно подключать наборы данных, устраняя необходимость в ручных шагах jailed и zfs jail. Перечислите наборы данных для делегирования в параметре zfs.dataset:
allow.mount; allow.mount.zfs; enforce_statfs = 1; zfs.dataset = "zroot/jails/data";
jail(8) присоединяет каждый перечисленный набор данных при запуске клетки, поэтому показанный выше хук exec.created больше не требуется. Этот параметр требует, чтобы было установлено значение allow.mount.zfs.
Для неустаревших менеджеров клеток, которые еще не понимают zfs.dataset, стартовый сценарий rc.d/jail также учитывает устаревшую переменную jail_<jailname>_zfs_dataset в /etc/rc.conf.
17.15.3. Доступ к снимкам изнутри клетки
Параметр zfs.mount_snapshot, доступный в FreeBSD 14.x и 15.x, позволяет пользователям внутри клетки получать доступ к содержимому снимков без делегирования всего набора данных. Когда он установлен в значение 1, пользователи клетки могут читать содержимое снимков файловой системы в её каталоге .zfs/snapshot:
zfs.mount_snapshot = 1;
Это удобно для восстановления отдельных файлов из снимков, сделанных на хост-системе. Если также установлено allow.mount.zfs, снимки могут быть дополнительно смонтированы внутри клетки. Свойство snapdir набора данных управляет тем, будет ли виден каталог .zfs.
Делегированный набор данных в сочетании с |
17.16. Менеджеры клеток и контейнеры
Как уже объяснялось ранее, каждый тип клетки FreeBSD может быть создан и настроен вручную, но в FreeBSD также существуют сторонние утилиты для упрощения настройки и администрирования.
Ниже приведён неполный список различных менеджеров клеток FreeBSD:
| Имя | Лицензия | Пакет | Documentation |
|---|---|---|---|
BastilleBSD | BSD-3 | ||
pot | BSD-3 | ||
cbsd | BSD-2 | ||
AppJail | BSD-3 | sysutils/appjail, для разработки sysutils/appjail-devel | |
iocage | BSD-2 | ||
ezjail |
FreeBSD публикует официальные OCI-образы базовой системы, начиная с FreeBSD 14.3-RELEASE, а OCI-контейнеры (стиль Docker), которые построены на той же технологии клеток и управляются с помощью инструментария Podman, рассматриваются в главе Контейнеры, которая дополняет обычные клетки, описанные здесь.
Изменено: 10 августа 2026 г. by Vladlen Popolitov