Обновление. Эта статья потеряла актуальность. Сейчас я не стал бы вручную собирать контейнер, а расчехлил бы докер, чтобы получить тот же самый результат. Тем не менее, она может быть полезной. Например, вы узнаете как сделать “докер руками”. Или может быть так, что докер вам по каким-то причинам не подходит, а изоляцию хочется.
Linux-контейнер — это линукс внутри линукса. Примерно как виртуализация (VirtualBox, Qemu), только без эмуляции железа. Для каких задач могут пригодиться контейнеры?
Когда хочется установить временно какой-то софт, не захлямляя основную ОС. Сделал контейнер, поработал, сохранил результат, удалил контейнер. Мусора в системе не осталось.
Когда нужна более свежая, или наоборот, устаревшая версия той или иной программы/библиотеки.
Когда нужного софта нет в репозиториях вашего дистрибутива, зато есть в репозиториях другого. Например мне пару раз нужен был
pdftk
, который в Archlinux есть в AUR, но не хочет собираться. Я нашёл готовый пакет в Debian и быстро установил его в контейнере.Когда надо потестить свежий выпуск Debian/Ubuntu/whatever.
Чтобы проверить работоспособность своего скрипта/приложения в другой среде, погонять тесты/бенчмарки.
Для сборки пакетов под другой дистрибутив.
Когда вам по работе нужен какой-нибудь oldstable Debian, недостойный быть основной системой на компьютере.
Для изоляции приложений. Заводим отдельный контейнер под Skype и не боимся его шпионских действий.
Эта инструкция описывает создание и использование контейнера на примере Debian Jessie. Создание контейнера с другим Linux-дистрибутивом ничем принципиально не отличается.
- Шаг 1. Debootstrap
- Шаг 2. Запуск контейнера
- Шаг 3. Первичная настройка системы
- Шаг 4. Доведение до ума
- Ссылки по теме
Нам понадобятся…
Любой дистрибутив под управлением systemd. Всё. В отличие от OpenVZ (другая система контейнерной виртуализации), для работы контейнеров не требуется кастомное ядро. В отличие от LXC… Не знаю, не смотрел LXC.
Запускать 32-битную систему можно как из 32-битной, так и из 64-битной. А вот 64-битную из 32-битной нельзя.
Для создания контейнера с Debian или Ubuntu понадобится утилита debootstrap
из одноимённого пакета. Он точно есть в Debian, Ubuntu, Archlinux и Gentoo. Наверняка есть и в других дистрибутивах. В конце концов это всего лишь набор shell-скриптов.
Где размещать контейнеры?
Там, где вам удобно. У меня контейнеры лежат в /home/chroot/
, потому что /home
вынесен на отдельный большой раздел и этот путь легко набирать на клавиатуре. Стандартным местом считается /var/lib/machines/
, поэтому я буду использовать его в этой инструкции.
Шаг 1. Debootstrap
Debootstrap разворачивает в указанном каталоге минимальный набор пакетов, необходимый для самостоятельной работы системы. Это самый важный шаг. Если сейчас допустить ошибку, то всё придётся переделывать сначала. Инструкцию я вынес в отдельный пост.
Рекомендую сделать бэкап сразу после этого шага. Я устанавливаю Debian Jessie, поэтому мои бэкапы содержат jessie в названии. Команды подсмотрены в Ubuntu community help wiki.
# cd /var/lib/machines
# tar cpzf jessie-deboostrapped.tar.gz --one-file-system -C jessie .
или
# tar cpjf jessie-deboostrapped.tar.bz2 --one-file-system -C jessie .
или
# tar cpJf jessie-deboostrapped.tar.xz --one-file-system -C jessie .
Здесь jessie
— это каталог с корневой ФС контейнера. У меня наименьший размер получился у .tar.xz
архива.
Восстановление из бэкапа:
# cd /var/lib/machines
# rm -rf jessie && mkdir jessie
# tar xpf /path/to/backup.tar.gz -C jessie --numeric-owner
или
# tar xpf /path/to/backup.tar.bz2 -C jessie --numeric-owner
или
# tar xpf /path/to/backup.tar.xz -C jessie --numeric-owner
Шаг 2. Запуск контейнера
Команды для 32-битной и 64-битной системы соответственно:
# cd /var/lib/machines
# linux32 systemd-nspawn -D jessie
# systemd-nspawn -D jessie
Я ставлю 32-битную, т.к. она занимает меньше места и не имеет ощутимых недостатков перед 64-битной.
По умолчанию в качестве имени контейнера будет использоваться имя каталога с системой. Если нужно другое, то его необходимо указать после ключа -M
. Имя будет использоваться для идентификации и в качестве хостнэйма.
Если systemd-nspawn ругается на machine ID и не стартует, просто создаём пустой файл:
# touch jessie/etc/machine-id
# linux32 systemd-nspawn -D jessie
Шаг 3. Первичная настройка системы
Все команды, которые здесь отмечены приглашением (chroot)#
, надо вводить в контейнере.
Устанавливать часовой пояс не надо, он возьмётся с хостовой системы. Имя хоста тоже задавать не надо.
Чтобы df
корректно работал, нужно сделать mtab:
(chroot)# cat >/etc/mtab <<EOF
rootfs / rootfs rw 0 0
EOF
Сеть должна работать без дополнительных манипуляций. Проверяем:
(chroot)# apt update
Устанавливаем локаль:
(chroot)# apt install locales
(chroot)# echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
(chroot)# locale-gen
(chroot)# update-locale LANG=en_US.UTF-8
- Вы можете не использовать
echo
, а раскомментировать необходимые локали в/etc/locale.gen
вручную. - Вместо
en_US.UTF-8
можно прописатьru_RU.UTF-8
, тогда всё будет по-русски. - Последние 3 команды можно заменить интерактивной
dpkg-reconfigure locales
.
Проверяем список доступных локалей и текущую локаль:
(chroot)# locale -a
(chroot)# locale
Локаль у рута будет пустой даже если перезайти в контейнер. Дело в том, что переменные окружения устанавливает не шелл, а процесс, который делает логин, а мы входим в контейнер без логина. У меня есть два решения:
- Вручную проэкспортировать все необходимые переменные окружения через шелл:
(chroot)# echo "export LANG=en_US.UTF-8" >> ~/.profile
(chroot)# source ~/.profile
- Входить в контейнер по ssh. Требует запущенного ssh-сервера в контейнере.
Конфигурируем менеджер пакетов
При необходимости добавляем репозитории, указываем локальное зеркало и т.д.
Спортсмены отключают установку рекомендованных пакетов:
(chroot)# echo 'APT::Get::Install-Recommends "false";' >>/etc/apt/apt.conf
(chroot)# echo 'APT::Get::Install-Suggests "false";' >>/etc/apt/apt.conf
Мне нравится устанавливать и обновлять пакеты без подтверждения Do you want to continue? [Y/n]
. Ведь если я приказал установить пакет, значит я в этом уверен и не надо переспрашивать. К тому же так быстрее получается. Отключаем подтверждение:
(chroot)# echo 'APT::Get::Assume-Yes "true";' >>/etc/apt/apt.conf
В простейшей конфигурации контейнера гостевая и хостовая система используют один и тот же сетевой стэк. Это значит, что если 22 порт уже занят ssh-сервером хостовой системы, то ssh-сервер гостевой системы не запустится. Необходимо в его настройках изменить номер порта. Это же справедливо для веб-серверов и прочих сервисов, работающих на стандартных портах.
Чтобы сервисы не стартовали сразу после установки пакетов:
(chroot)# cat > /usr/sbin/policy-rc.d <<EOF
#!/bin/sh
exit 101
EOF
(chroot)# chmod a+x /usr/sbin/policy-rc.d
Самое время сделать второй бэкап:
# tar cpJf jessie-configured.tar.xz --exclude='./var/cache/apt/archives/*.deb' \
--exclude='./var/lib/apt/lists/*' --exclude='./var/cache/apt/*.bin' \
--one-file-system -C jessie .
Чтобы архив занимал меньше места, мы исключаем:
/var/cache/apt/archives/*.deb
— кэш deb-пакетов apt’а,
/var/lib/apt/lists/*
— сохранённые индексы репозиториев (что лежит в таком-то репозитории),
/var/cache/apt/*.bin
— какая-то база данных apt’а.
Шаг 4. Доведение до ума
Дополнительные пакеты, которые могут понадобиться:
build-essential
для сборки deb-пакетов
cron
— планировщик задач
file
— утилита для определения типа файла
less
— утилита просмотра текста с возможностью скроллить вверх и вниз
logrotate
nano
— простенький консольный текстовый редактор
ncurses-term
для поддержки терминала rxvt-unicode-256color и других
openssh-server
rsync
— мощная утилита синхронизации файлов и каталогов, в т.ч. по сети
sudo
vim
или vim-tiny
zsh
Напоминаю, что посмотреть описание пакета можно командой
(chroot)# apt show ПАКЕТ
или
# linux32 systemd-nspawn -D jessie apt show ПАКЕТ
По умолчанию при старте контейнера запускается bash --login
от рута, независимо от установленного шелла. Как получить нужный шелл? Можно указать команду для запуска в качестве аргумента:
# systemd-nspawn -D jessie /usr/bin/zsh
Но писать такую длинную команду вам быстро надоест, поэтому применим хак:
(chroot)# echo "exec zsh --login" >> ~/.profile
Это позволит входить в контейнер как обычно, но сразу получать zsh вместо bash.
Создаём пользователя vas, входящего в группу sudo
. Вы можете создать другого :)
(chroot)# useradd -m -g users -G sudo -s /usr/bin/zsh vas
(chroot)# passwd vas
Переключение с рута на пользователя делается командой:
(chroot)# su - vas
Иногда бывает удобно сделать sudo без ввода пароля. На хостовой системе я себе таких шалостей не позволяю, а в контейнере можно. Не редактируйте /etc/sudoers
напрямую! Используйте команду visudo
.
Разрешаем sudo без пароля для всех пользователей, входящих в группу sudo
:
В качестве вишенки на торте возьмём zshrc, vimrc и т.п. с хостовой системы. Теперь в контейнере есть всё необходимое для комфортной работы.
Напоследок можно немного облегчить систему за счёт man-страниц, документации, локалей. Это для особо целеустремлённых спортсменов.
(chroot)# rm -rf /usr/share/doc/*
(chroot)# find /usr/share/locale -maxdepth 1 -mindepth 1 ! -name en_US -exec rm -rf {} \;
(chroot)# find /usr/share/i18n/locales -maxdepth 1 -mindepth 1 ! -name en_US -exec rm -rf {} \;
(chroot)# rm -rf /usr/share/man/*
(chroot)# rm -rf /usr/share/groff/*
(chroot)# rm -rf /usr/share/info/*
(chroot)# rm -rf /usr/share/lintian/*
(chroot)# rm -rf /usr/include/*
И последний бэкап на сегодня:
# tar cpJf jessie-vas.tar.xz --exclude='./var/cache/apt/archives/*.deb' \
--exclude='./var/lib/apt/lists/*' --exclude='./var/cache/apt/*.bin' \
--one-file-system -C /var/lib/machines/jessie .
Всё, контейнер jessie готов к бою! А благодаря бэкапам, в любой момент можно откатиться к чистому состоянию или сделать ещё несколько однотипных контейнеров.
Ссылки по теме
- systemd for Administrators, Part VI. Chroot. Статья про systemd-nspawn лично от Леннарта Поттеринга из цикла systemd for Administrators. Сергей Пташник перевёл статьи на русский язык. Актуальная версия перевода доступна здесь.
- Markus Lindenberg. Debian Containers with systemd-nspawn.
- Creating containers with systemd-nspawn.
- Linux-контейнеры дома: зачем и как. Блог компании WestComp на хабре.
- Systemd и контейнеры: знакомство с systemd-nspawn. Блог компании Селектел на хабре.