Linux-контейнеры дома: зачем и как

от автора

Рассуждения

При упоминании словосочетания «контейнерная виртуализация», многим на ум сразу же приходят Virtuozzo и OpenVZ, а также Docker. Ассоциируется же это все, в первую очередь, с хостингом, VPS и другими подобными вещами.

Дома, на личных компьютерах многие используют виртуальные машины: в первую очередь, пожалуй, Virtualbox. Как правило, для того, чтобы работая под Linux, иметь под рукой Windows или наоборот. Однако, при наличии множества родственных Linux-операционок, я стал замечать, что использование виртуальных машин — это, мягко говоря, нерационально.


В первую очередь, очень быстро расходуется дисковое пространство. Каждой виртуальной машине нужно место, даже если несколько из них отличаются только конфигами. Особенно критично это на не великих размеров SSD лаптопа. В принципе, Virtualbox умеет работать с raw-девайсами и, теоретически, машинам можно назначать rw LVM-снапшот, но тут опять же встают вопросы с изменением размера файловой системы в дальнейшем, автоматизацией клонирования, переноса, удаления и тому подобное.

Во вторую — это больший расход оперативной памяти. В третью — не самые удобные инструменты взаимодействия…

Потому, возникла идея опробовать в домашних условиях контейнерную виртуализацию. OpenVZ отмел сразу, по причине необходимости возиться с кастомным ядром. Выбор же пал на LXC, поставляющийся в репозитарии стабильного Debian’a.

Зачем это нужно:
— Для сборки ПО при нежелании захламлять разномастными *-dev пакетами основную рабочую систему.
— Потребность в другом дистрибутиве для запуска каких-либо специфических программ и, опять же, сборки.
— Изоляция потенциально небезопасного софта, вроде того же скайпа совершающего разные непонятные действия в домашнем каталоге пользователя и всяких сомнительных веб-технологий: уязвимость во флеше, в java, в обработчике pdf — это только то, что плавает на поверхности.
— Анонимность. Эдак можно банально остаться залогиненым в своей любимой социалочке, забыть подчистить куки или оказаться незнакомым с очередной новой веб-технологией вроде этой webrtc. Можно, конечно, держать несколько профилей браузера, но от перечисленных выше дыр и технологий это не защитит.

Итак, рассмотрим плюсы и минусы LXC:
+ Работает на ванильном ядре
+ Простота проброса устройств и каталогов хоста, так как работает это все через cgroups
+ Очень нетребовательно к ресурсам, в отличии от виртуальных машин типа Virtualbox или qemu

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

Развертывание и настройка контейнера

В первую очередь, ставим пакет lxc и все необходимые утилиты:

sudo apt-get install lxc bridge-utils

Смотрим доступные группы томов LVM:

$sudo vgs   VG         #PV #LV #SN Attr   VSize   VFree   nethack-vg   1   6   0 wz--n- 119,00g 7,36g 
sudo lxc-create -t debian -B lvm --vgname nethack-vg --fssize 2G -n deb_test

Указываем использовать LVM в качестве системы хранения, Volume Group ( в моем случае — nethack-vg) и размер 2 гигабайта, иначе по умолчанию будет создан одногиговый том. Хотя, если вдруг стало тесновато, можно будет сделать lvresize.

Смотрим:

$sudo lvs   LV   VG         Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert   deb_test nethack-vg -wi-ao----   2,00g   home     nethack-vg -wi-ao----  93,09g   root     nethack-vg -wi-ao----   8,38g   tmp      nethack-vg -wi-ao---- 380,00m   var      nethack-vg -wi-ao----   2,79g   vm       nethack-vg -wi-ao----   5,00g 

Видим, что у нас появился том deb_test.

Типовой конфиг, созданный скриптом:

/var/lib/lxc/deb_test/config

# Template used to create this container: /usr/share/lxc/templates/lxc-debian # Parameters passed to the template: # For additional config options, please look at lxc.container.conf(5) lxc.network.type = empty lxc.rootfs = /dev/nethack-vg/deb_test  # Common configuration lxc.include = /usr/share/lxc/config/debian.common.conf  # Container specific configuration lxc.mount = /var/lib/lxc/deb_test/fstab lxc.utsname = deb_test lxc.arch = amd64 lxc.autodev = 1 lxc.kmsg = 0 

Стартуем:

sudo lxc-start -n deb_test


Залогинимся с указанным паролем. Для запуска в headless-режиме используется ключ -d, а рутовую консоль можно получить с помощью команды

sudo lxc-attach -n deb_test

Пока у нас ни сети, ни нужных для работы программ. Для этого на хосте поднимаем мост, задаем IP, заворачиваем трафик из подсети виртуалки, при отключении интерфейса разрушаем мост.

На хосте прописываем в /etc/network/interfaces

auto lo br0  iface br0 inet static    address 172.20.0.1    netmask 255.255.255.0    pre-up  /sbin/brctl addbr br0    post-up /sbin/brctl setfd br0 0    post-up iptables -t nat -A POSTROUTING -s 172.20.0.0/24 -j MASQUERADE    post-up echo 1 > /proc/sys/net/ipv4/ip_forward    pre-down /sbin/brctl delbr br0 

В конфиг контейнера дописываем:

lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.hwaddr = 00:01:02:03:04:05 

Чтобы сразу получить рабочую сеть и возможность установки пакетов apt’ом, допишем

lxc.network.ipv4 = 172.20.0.3 lxc.network.ipv4.gateway = 172.20.0.1 

И выполним

echo "nameserver 192.168.18.1">/etc/resolv.conf

Понятно, что 192.168.18.1 — IP моего DNS.

Установим нужные пакеты:

#apt-get install vim openvpn zsh iftop

Дальше либо на хосте, либо на другой рабочей виртуалке можно получить список установленных пакетов и установить их все в нашем новом контейнере:

scp user@172.20.0.2:/etc/apt/sources.list /etc/apt/ scp -r user@172.20.0.2:/etc/apt/sources.list.d /etc/apt/ apt-get update ssh user@172.20.0.2 'dpkg --get-selections|grep -v deinstall'|dpkg --set-selections apt-get dselect-upgrade 

Теперь можно по-человечески настроить сетевой интерфейс в контейнере, использовав любимый текстовый редактор:

/etc/network/interfaces:

auto lo eth0 iface lo inet loopback  iface eth0 inet static address 172.20.0.3 netmask 255.255.255.0 gateway 172.20.0.1 dns-nameservers 192.168.18.1 

Впрочем, это можно было сделать с хост-системы, например, смонтировав логический том. Способов много.

В принципе, в качестве DNS можно указать любой публичный, если не опасаетесь за свою приватность. Например, гугловские 8.8.8.8 и 8.8.4.4.

По доступу к устройствам хост-системы, я придерживаюсь политики «все, что не разрешено, запрещено». Добавим для этого следующую строчку в конфиг:

lxc.cgroup.devices.deny = a 

Удаляем

lxc.include = /usr/share/lxc/config/debian.common.conf

Попробуем подключиться через OpenVPN. Сразу же получаем ошибку:

Thu Oct 15 16:39:33 2015 ERROR: Cannot open TUN/TAP dev /dev/net/tun: No such file or directory (errno=2) Thu Oct 15 16:39:33 2015 Exiting due to fatal error 

Система пишет, что интерфейсы TUN/TAP недоступны по причине их отсутствия. Очевидно, что нужно разрешить гостевой системе использовать устройства хоста. Открываем конфигурационный файл контейнера, /var/lib/lxc/deb_test/config и добавляем туда строчку:

lxc.cgroup.devices.allow = c 10:200 rwm  

В контейнере выполняем:

root@deb_test:/# mkdir /dev/net; mknod /dev/net/tun c 10 200 root@deb_test:/# echo 'mkdir /dev/net; mknod /dev/net/tun c 10 200; exit 0'>/etc/rc.local 

Обратим внимание на 10:200 — это идентификатор типа устройств. Если выполним на хосте:

$ls -l /dev/net/tun crw-rw-rw- 1 root root 10, 200 окт 13 10:30 /dev/net/tun 

То увидим идентификаторы 10, 200. По ним и будем ориентироваться, разрешая доступ к устройства, например камере — video0.

lxc.cgroup.devices.allow = c 81:* rwm 

Точно также добавляем остальные нужные устройства:

# /dev/null and zero lxc.cgroup.devices.allow = c 1:3 rwm lxc.cgroup.devices.allow = c 1:5 rwm # consoles lxc.cgroup.devices.allow = c 5:1 rwm lxc.cgroup.devices.allow = c 5:0 rwm lxc.cgroup.devices.allow = c 4:0 rwm lxc.cgroup.devices.allow = c 4:1 rwm # /dev/{,u}random lxc.cgroup.devices.allow = c 1:9 rwm lxc.cgroup.devices.allow = c 1:8 rwm lxc.cgroup.devices.allow = c 136:* rwm lxc.cgroup.devices.allow = c 5:2 rwm # rtc lxc.cgroup.devices.allow = c 254:0 rm #usb passthrough lxc.cgroup.devices.allow = c 189:* rwm #video lxc.cgroup.devices.allow = c 81:* rwm #sound lxc.cgroup.devices.allow = c 116:* rwm lxc.cgroup.devices.allow = c 14:* rwm 

Для функционирования иксов и возможности их проброса через ssh, нужно добавить точку монтирования:

lxc.mount.entry = /tmp/.X11-unix/X0 tmp/.X11-unix/X0 none bind,optional,create=file 

По аналогии можно примонтировать и другие, нужные каталоги и файлы:

lxc.mount.entry = /home/user/.vim home/user/.vim none bind,optional,create=dir 0 0  lxc.mount.entry = /home/user/.vimrc home/user/.vimrc none bind,optional,create=file 0 0  

Для воспроизведения звука, можно разрешить доступ к звуковому устройству, если карта многопоточная (с однопоточной при использовании dmix возникают проблемы с блокировкой):

lxc.cgroup.devices.allow = c 116:* rwm lxc.cgroup.devices.allow = c 14:* rwm lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir 0 0  

А можно настроить pulseaudio на воспроизведение звука по сети, как это описано здесь. Кратко:

Отредактировать на хосте /etc/pulse/default.pa, дописав туда:

load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;172.20.0.3 auth-anonymous=1 

В итоге, у нас получается вот такой конифиг:

/var/lib/lxc/deb_test/config

lxc.network.type = empty lxc.rootfs = /dev/nethack-vg/deb_test  lxc.mount = /var/lib/lxc/deb_test/fstab lxc.utsname = deb_test lxc.arch = amd64 lxc.autodev = 1 lxc.kmsg = 0  lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.hwaddr = 00:01:02:03:04:05  lxc.network.ipv4 = 172.20.0.3 lxc.network.ipv4.gateway = 172.20.0.1  #deny acces for all devices lxc.cgroup.devices.deny = a  # /dev/null and zero lxc.cgroup.devices.allow = c 1:3 rwm lxc.cgroup.devices.allow = c 1:5 rwm # consoles lxc.cgroup.devices.allow = c 5:1 rwm lxc.cgroup.devices.allow = c 5:0 rwm lxc.cgroup.devices.allow = c 4:0 rwm lxc.cgroup.devices.allow = c 4:1 rwm # /dev/{,u}random lxc.cgroup.devices.allow = c 1:9 rwm lxc.cgroup.devices.allow = c 1:8 rwm lxc.cgroup.devices.allow = c 136:* rwm lxc.cgroup.devices.allow = c 5:2 rwm # rtc lxc.cgroup.devices.allow = c 254:0 rm  #sound lxc.cgroup.devices.allow = c 116:* rwm lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir 0 0  #tun/tap adapters lxc.cgroup.devices.allow = c 10:200 rwm  #video0 lxc.cgroup.devices.allow = c 81:* rwm lxc.mount.entry = /dev/video0 dev/video0 none bind,optional,create=file  lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir lxc.mount.entry = /tmp/.X11-unix/X0 tmp/.X11-unix/X0 none bind,optional,create=file  

Контейнер готов к использованию.

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

Доустановим, например, i2p с Tor’ом, если не сделали этого ранее, и сходу настроим privoxy:

wget -q https://geti2p.net/_static/i2p-debian-repo.key.asc -O- | sudo apt-key add - echo "deb http://deb.i2p2.no/ jessie main" >/etc/apt/sources.list.d/i2p.list echo "deb-src http://deb.i2p2.no/ jessie main" >>/etc/apt/sources.list.d/i2p.list apt-get update apt-get install privoxy i2p tor 

/etc/privoxy/config

user-manual /usr/share/doc/privoxy/user-manual confdir /etc/privoxy logdir /var/log/privoxy actionsfile user.action      # User customizations filterfile default.filter filterfile user.filter      # User customizations logfile logfile listen-address  localhost:8118 toggle  1 enable-remote-toggle  1 enable-remote-http-toggle  1 enable-edit-actions 1 enforce-blocks 0 buffer-limit 4096 enable-proxy-authentication-forwarding 0 forwarded-connect-retries  0 accept-intercepted-requests 0 allow-cgi-request-crunching 0 split-large-forms 0 keep-alive-timeout 5 tolerate-pipelining 1 socket-timeout 300 forward .i2p localhost:4444 forward-socks5 .onion localhost:9050 . 

Запускать графические приложения вроде браузера удобнее всего через ssh:

ssh -Y 172.20.0.2 "PULSE_SERVER=172.20.0.1 http_proxy=127.0.0.1:8118 chromium" 

Так же, разумеется, LXC предоставляет средства для клонирования контейнеров и снятия снапшотов.

Так, например, склонировать контейнер, файловая система которого будет являться LVM-снапшотом можно командой:

sudo lxc-clone -s -H -o deb_test -L 200M --new deb_test2 

Будет создан контейнер deb_test2 с файловой системой, размещенной на LVM-снапшоте размером 200MB (под хранение diff’ов). Это будет точная копия deb_test, над которой можно провести пару экспериментов и, например, безболезненно удалить.

А вот lxc-snapshot с LVM в качестве хранилища, на версии lxc-1.0.6 почему-то не работает:

->sudo lxc-snapshot -n deb_test  	lxc_container: deb_test's backing store cannot be backed up. 	lxc_container: Your container must use another backing store type. 	lxc_container: Error creating a snapshot 

Проблема описывается и обсуждается здесь. Потому, снимки придется делать по старинке:

sudo lvcreate -L100M -s -n deb_test_before_rm_rf -p r /dev/nethack-vg/deb_test 

В данном случае, создали read-only снапшот с именем deb_test_before_rm_rf размером 100MB. Что с ним делать дальше? Например, его можно сдампить посредством dd, перенести на другую машину вместе с конфигами контейнера, создать там том нужного размера и пролить тем же dd (cp, cat, итд) — эдакая «живая миграция».

Как писалось выше, областей применения контейнерам можно найти массу. Но главной, при домашнем использовании, на мой взгляд, является изоляция приложений.

На этом пока все.

ссылка на оригинал статьи http://habrahabr.ru/post/269423/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *