Установка и настройка LXC под Ubuntu 22.04. Непривилегированные контейнеры.

Перед настройкой LXC рекомендуется выполнить базовую настройку Ubuntu .

Воспользуйтесь инструкцией для настройки nvidia в LXC

UID и GID Maping

Убедитесь, что у вас корректно настроены map uig и gid. Mapping нужен для того, чтобы запускать непривелигированные контейнера. Т.е. root в контейнере на хост машине будет работать с ID 100000, а не 0. Соостветственно файлы в контейнеры будут иметь владельца, начиная с 100000.

nano /etc/subuid

_x000D_lxc:100000:65536_x000D_lxd:100000:65536_x000D_root:100000:65536

nano /etc/subgid

_x000D_lxc:100000:65536_x000D_lxd:100000:65536_x000D_root:100000:65536

Для удобства вы можете добавить пользователя lxc-root, чтобы в htop видеть процессы запущенные в lxc

_x000D_groupadd -r --gid 100000 lxc-root_x000D_useradd -r -M --uid 100000 -g lxc-root lxc-root

Установка LXC

_x000D_aptitude install lxc

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

_x000D_chown lxc-root:root /var/lib/lxc_x000D_chmod 755 /var/lib/lxc

Также вам потребуется настроить UID для LXC. Пропишите в конце файла следующие строки, выполнив команду nano /etc/lxc/default.conf

_x000D_lxc.idmap = u 0 100000 65536_x000D_lxc.idmap = g 0 100000 65536

Настройка сети

Рекомендуется использовать сеть 172.30.0.1/24. Более подробный список указан в списке сетей .

В файле /etc/default/lxc-net пропишите

_x000D_USE_LXC_BRIDGE="true"_x000D_LXC_BRIDGE="lxcbr0"_x000D_LXC_ADDR="172.30.0.1"_x000D_LXC_NETMASK="255.255.255.0"_x000D_LXC_NETWORK="172.30.0.0/24"_x000D_LXC_DHCP_RANGE="172.30.0.2,172.30.0.254"_x000D_LXC_DHCP_MAX="253"_x000D_LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf_x000D_#LXC_DOMAIN="lxc"

Создайте файл /etc/lxc/dnsmasq.conf и пропишите в нем:

_x000D_port=53_x000D_listen-address=172.30.0.1_x000D_resolv-file=/etc/resolv.conf_x000D_domain-needed

Если у вас уже запущен dnsmasq на 53 порту, то можно изменить порт на 53172

_x000D_port=53172

Включите драйвера br_netfilter

_x000D_echo overlay >> /etc/modules-load.d/docker.conf_x000D_echo br_netfilter >> /etc/modules-load.d/docker.conf

Установка контейнера

Установка контейнера LXC Centos 7:

_x000D_lxc-create -t download -n test-centos -- --dist centos --release 7 --arch amd64

Установка контейнера LXC Ubuntu 22.04:

_x000D_lxc-create -t download -n test-ubuntu -- --dist ubuntu --release bionic --arch amd64

Установка контейнера LXC Ubuntu 24.04:

_x000D_lxc-create -t download -n test-ubuntu -- --dist ubuntu --release noble --arch amd64

Установка контейнера LXC Debian Jessie:

_x000D_lxc-create -t download -n test-debian -- --dist debian --release jessie --arch amd64

Установка контейнера Alpine Linux 3.10:

_x000D_lxc-create -t download -n test-alpine -- --dist alpine --release 3.10 --arch amd64

Список шаблонов: https://us.images.linuxcontainers.org/

Если выдает ошибку «ERROR: Unable to fetch GPG key from keyserver» то нужно прописать keyserver:

_x000D_lxc-create -t download -n test-ubuntu-focal -- --dist ubuntu --release focal --arch amd64 --keyserver hkp://keyserver.ubuntu.com

Настройка nested контейнера

Nested контейнер — это возможность запустить контейнер в контейнере. Например, если вам нужно будет запустить Docker внутри LXC контейнера, то нужно включить данную опцию.

Опция включается в файле конфига контейнера /var/lib/lxc/<название контейнера>/config

Раскоментируйте строчку:

_x000D_#lxc.include = /usr/share/lxc/config/nesting.conf

Также может понадобится прописать параметр для монтирования файловой системы cgroup

_x000D_lxc.mount.auto = cgroup-full:rw

Настройка сети контейнера

В конце файла настроек контейнера /var/lib/lxc/<название контейнера>/config укажите слоедующие параметры:

_x000D_# Network configuration_x000D_lxc.net.0.type = veth_x000D_lxc.net.0.link = lxcbr0_x000D_lxc.net.0.flags = up_x000D_lxc.net.0.hwaddr = 00:16:3e:6b:aa:11_x000D_lxc.net.0.ipv4.address = 172.30.0.10/24_x000D_lxc.net.0.ipv4.gateway = 172.30.0.1

172.30.0.10 — Это IP адрес контейнера
172.30.0.1 — Адрес шлюза
00:16:3e:6b:aa:11 — MAC Адрес должен быть уникальный
lxcbr0 — Имя LXC bridge. Обычно ставится автоматически

Настройка IP адреса для контейнера с Alpine Linux

Бывает, что первого способа не достаточно чтобы выдать IP адрес. Тогда нужно задать IP адрес в самом контейнере.

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

_x000D_lxc-attach название контейнера

Откройте файл /etc/network/interfaces

Вместо iface eth0 inet dhcp Пропишите:

_x000D_iface eth0 inet static_x000D_ address 172.30.0.10_x000D_ netmask 255.255.255.0_x000D_ gateway 172.30.0.1

Выйдите из контейнера командой:

_x000D_exit

Перезапустить контейнер:

_x000D_lxc-stop название контейнера_x000D_lxc-start название контейнера

Настройка IP адреса для контейнера с Centos

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

_x000D_lxc-attach название контейнера

Для Centos7 в файле /etc/sysconfig/network-scripts/ifcfg-eth0 укажите

_x000D_DEVICE=eth0_x000D_ONBOOT=yes_x000D__x000D_IPADDR=172.30.0.20_x000D_NETMASK=255.255.255.0_x000D_GATEWAY=172.30.0.1_x000D_DNS1=172.30.0.1_x000D__x000D_#BOOTPROTO=dhcp_x000D_HOSTNAME=test-centos_x000D_NM_CONTROLLED=no_x000D_TYPE=Ethernet_x000D_MTU=_x000D_DHCP_HOSTNAME=`hostname`

Настройка IP адреса для контейнера с Ubuntu

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

_x000D_lxc-attach название контейнера

Откройте файл nano /etc/netplan/10-lxc.yaml и пропишите следующее содержимое

_x000D_network:_x000D_ version: 2_x000D_ ethernets:_x000D_ eth0:_x000D_ dhcp4: no_x000D_ dhcp6: no_x000D_ addresses: [172.30.0.20/24]_x000D_ gateway4: 172.30.0.1_x000D_ nameservers:_x000D_ addresses: [172.30.0.1]

Если IP адрес был задан в адресе конфига, то в netplan их можно не указывать.

Перезапустить контейнер:

_x000D_lxc-stop название контейнера_x000D_lxc-start название контейнера

Настройка DNS

Подключитесь к контейнеру и удалите файл resolv

_x000D_rm -f /etc/resolv.conf

И создайте его заново:

nano /etc/resolv.conf

_x000D_nameserver 172.30.0.1_x000D_

Перенос папки на другой диск

К примеру, вам нужно перенести папку lxc в /srv.

Перед переносом папки, остановите все контейнеры.

Создайте папку lxc в srv

_x000D_mkdir /srv/lxc_x000D_chown lxc-root:root /srv/lxc_x000D_chmod 755 /srv/lxc

перенесите все содержимое из папки /var/lib/lxc в /srv/lxc

_x000D_mv -f /var/lib/lxc/* /srv/lxc

Убедитесь что папка /var/lib/lxc пустая

_x000D_ls -la /var/lib/lxc

/etc/fstab пропишите строчку в конце

_x000D_/srv/lxc /var/lib/lxc none bind

Сделайте монтирование папки:

_x000D_mount -a

По умолчанию при загрузке будет монтироваться папка

Перенос контейнера на другой хост

Остановите контейнер:

_x000D_lxc-stop название_контейнера

Создайте на другом сервере папку:

_x000D_/var/lib/lxc/название_контейнера/

Перенесите контейнер через rsync:

_x000D_rsync -aSsuh --info=progress2 --numeric-ids /var/lib/lxc/название_контейнера/ server:/var/lib/lxc/название_контейнера/

Автозапуск контейнера

Чтобы настроить автоматическое включение контейнера, укажите следующие строки для файла /var/lib/lxc/<название контейнера>/config :

_x000D_lxc.start.auto = 1_x000D_lxc.start.delay = 5 # Задержка, когда будет запущен контейнер

Если хотите, чтобы контейнер не запускался при старте, укажите 0

Ограничение ресурсов CPU

Иногда нужно ограничить cpu для контейнера. Чтобы это сделать, пропишите строчку в конфиге контейнера

_x000D_# CPU Limit_x000D_lxc.cgroup.cpuset.cpus = 0,1

0,1 — означает запустить контейнер на 1м и 2м ядре.

Отключение AppArmor в LXC

Иногда AppArmor мешает контейнеру запуститься. Тогда в конце файла настроек контейнера /var/lib/lxc/<название контейнера>/config пропишите следующую строку

Прописывайте, только если контейнер не запускается.

_x000D_lxc.apparmor.profile = unconfined

Команды для работы с контейнерами

Чтобы запустить контейнер выполните:

_x000D_lxc-start название контейнера

Чтобы остановить контейнер выполните:

_x000D_lxc-stop название контейнера

Чтобы подключиться к контейнеру под рутом:

_x000D_lxc-attach название контейнера

Просмотреть список контейнеров и их IP адреса

_x000D_lxc-ls -f

Установка SSH

С хоста. Сгенерируйте ключ ssh, если его у вас нет в домашней папке:

_x000D_ssh-keygen

Установите ваш публичный сертификат в контейнер:

_x000D_mkdir -p /var/lib/lxc/test-ubuntu/rootfs/root/.ssh/_x000D_cat ~/.ssh/id_rsa.pub >> /var/lib/lxc/test-ubuntu/rootfs/root/.ssh/authorized_keys_x000D_chown -R lxc-root:lxc-root /var/lib/lxc/test-ubuntu/rootfs/root/.ssh_x000D_chmod 700 /var/lib/lxc/test-ubuntu/rootfs/root/.ssh_x000D_chmod 400 /var/lib/lxc/test-ubuntu/rootfs/root/.ssh/authorized_keys

Подключитесь к контейнеру через консоль командой:

_x000D_lxc-attach test-ubuntu

Установите SSH сервер в контейнере.

Для Ubuntu:

_x000D_apt install openssh-server -y

Для Centos:

_x000D_yum install openssh-server -y_x000D_systemctl enable sshd

Установите root пароль:

_x000D_passwd

Завершите текущий сеанс в контейнере:

_x000D_exit

Теперь вы можете подключиться к контейнеру через SSH:

_x000D_ssh root@IP-адрес-контейнера

Проброс портов

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

Чтобы пробросить порты, нужно установить и настроить iptables-persistent

При работе с iptables будьте осторожны.
Одно неверное движение и доступ к серверу может быть заблокирован !!!

После этого в файле /etc/iptables/rules.v4 и /etc/iptables/rules.v6 в секцию *nat нужно указать строчки

_x000D_# Проброс SSH на 172.30.0.10_x000D_-A PREROUTING ! -i lxcbr0 -p tcp -m tcp --dport 22340 -j DNAT --to-destination 172.30.0.10:22_x000D__x000D_# Проброс HTTP на 172.30.0.10_x000D_-A PREROUTING ! -i lxcbr0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.30.0.10:80_x000D_-A PREROUTING ! -i lxcbr0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 172.30.0.10:443_x000D__x000D_# Проброс FTP на 172.30.0.10_x000D_-A PREROUTING ! -i lxcbr0 -p tcp -m tcp --dport 21 -j DNAT --to-destination 172.30.0.10:21_x000D_-A PREROUTING ! -i lxcbr0 -p tcp -m tcp --dport 30000:50000 -j DNAT --to-destination 172.30.0.10:30000-50000_x000D__x000D_

и выполнить:

_x000D_iptables-restore < /etc/iptables/rules.v4_x000D_ip6tables-restore < /etc/iptables/rules.v6_x000D_systemctl stop lxc_x000D_systemctl stop lxc-net_x000D_systemctl start lxc-net_x000D_systemctl start lxc