Установка и настройка lxc контейнеров на Centos 7
Я давно хотел посмотреть какую-нибудь систему контейнеризации, отличную от docker, так как очень его не люблю. Решил в итоге остановиться для начала на lxc, познакомиться, рассказать вам, как установить и настроить lxc на CentOS 7. Впечатления у меня от него не однозначные, расскажу обо всем по порядку.
Если у вас есть желание научиться администрировать системы на базе Linux, рекомендую познакомиться с онлайн-курсом «Linux для начинающих» в OTUS. Курс для новичков, для тех, кто с Linux не знаком. Подробная информация.
Введение
Сразу предупреждаю, что данная статья это мое знакомство с lxc контейнерами. Я не имею практического опыта работы с ними, поэтому бездумно брать и применять мои рекомендации не стоит.
Не буду много писать о том, что такое контейнеры, чем они отличаются от виртуальных машин, и чем отличаются системы контейнеров (lxc, docker, openvz и др.) друг от друга. Все это можно найти в интернете на сайтах самих продуктов. Расскажу все своими словами.
- Главное отличие контейнера от виртуальной машины в том, что он запускается на том же уровне железа, что и хостовый сервер. Нет необходимости в виртуальных устройствах. Контейнер видит исходное железо. Это плюс к производительности. Используется ядро исходной системы и изоляция ресурсов внутри системы.
- Контейнер может масштабироваться по ресурсам до целого физического сервера. Например, контейнер может использовать тот же диск и файловую систему, что и хостовая машина. Нет необходимости разбивать диск на кусочки, как с виртуальными машинами и давать каждому по кусочку. В итоге, кто-то может свой диск вообще не использовать, а кому-то не хватит. С контейнерами можно поступить проще — все используют общий диск с хостом. Ограничений для диска как в виртуальной машине тем не менее все равно можно устанавливать. То же самое можно сделать с процессором и памятью.
Я почти не работал с контейнерами, кроме докера. С ним приходится работать только в связке с разработчиками. Для своих целей я его не использую, так как для моих задач он мне кажется неудобным. Не хочется сейчас здесь раскрывать эту тему, может быть в другой раз в статье о докер, если таковая будет. Но в целом докер я не люблю, особенно в продакшене.
Расскажу о том, почему мне захотелось посмотреть на контейнеры вместо виртуальных машин, которые использую повсеместно уже много лет.
- Как уже написал ранее, привлекает возможность использовать ресурсы хостовой машины напрямую. Взял системный диск с корнем / на 1Тб и все контейнеры его используют пока есть место.
- Легкий бэкап и доступ к файлам в контейнерах. Посмотреть файлы в контейнере можно просто зайдя в директорию контейнера с хостовой машины. Они все хранятся в открытом виде. Так их очень удобно бэкапить с помощью rsync, или каким-то другим способом.
- Легко копировать, разворачивать, управлять контейнерами. Они занимают мало места, можно руками с хоста поправить какой-то конфиг в системе контейнера.
Например, у меня есть достаточно мощные VDS серверы от ihor. 2 ядра, 8 гигов, 150Гб диск. Иногда то, что там размещается, не использует полностью ресурсы виртуальной машины. Хочется как-то их занять, но при этом никак не затрагивать основные проекты на виртуальной машине. Иногда хочется какие-то тестовые среды создавать для сайтов и пробовать новые версии софта. Для этого надо отдельную виртуалку брать. Вместо этого я решил попробовать lxc контейнеры.
Использовать lxc контейнеры в плане сети можно двумя способами:
- Заказывать каждому контейнеру отдельный внешний IP, настраивать для контейнера bridge на реальном сетевом интерфейсе и выпускать его напрямую в интернет. Этот вариант подходит, если есть ip адреса или не жалко для них денег. Так работать удобнее всего.
- Настраивать виртуальный bridge, настраивать NAT и проброс портов с хостовой машины внутрь контейнеров. Не очень удобно, но тем не менее вполне рабочий вариант.
Я расскажу про оба способа, так как проверял и то и другое. Настраивать все будем на CentOS 7.
Если у вас еще нет своего сервера с CentOS 8, то рекомендую мои материалы на эту тему:
Настройка сети для LXC контейнеров
Начнем с настройки сети для контейнеров. Нам понадобится пакет bridge-utils. Установим его:
Настроим виртуальный бридж, который будут использовать только контейнеры внутри своей виртуальной сети — 10.1.1.1/24. Для этого создаем в директории /etc/sysconfig/network-scripts файл ifcfg-virbr0 следующего содержания:
# mcedit /etc/sysconfig/network-scripts/ifcfg-virbr0
DEVICE=virbr0 BOOTPROTO=static IPADDR=10.1.1.1 NETMASK=255.255.255.0 ONBOOT=yes TYPE=Bridge NM_CONTROLLED=no
После изменения сетевых настроек лучше перезагрузиться. Проверим, что получилось:
Дальше нам может помочь статья по настройке шлюза на centos, так как часть функционала шлюза нам нужно будет реализовать на хосте. А именно:
- Включить маршрутизацию пакетов между сетевыми интерфейсами
- Настроить NAT для виртуальной сети контейнера
- Настроить проброс портов в контейнеры
Включаем маршрутизацию пакетов. Для этого в файл /etc/sysctl.conf добавляем строку в самый конец:
Теперь основное — настройка iptables. Вообще, она сходу не берется и чаще всего у людей возникают вопросы по работе, если настраивают первый раз. В CentOS 7 по-умолчанию установлен firewalld. Я не использую его и всегда отключаю. Не потому, что он плохой и неудобный, а потому, что привык работать с iptables напрямую, у меня много готовых конфигурация для него.
# systemctl stop firewalld # systemctl disable firewalld
Устанавливаем службы iptables:
# yum install iptables-services
Рисуем конфиг для iptables. Пример взял из статьи про настройку шлюза для локальной сети, только изменил адрес виртуальной сети и имя интерфейса. По сути нам нужно то же самое. Привожу конфиг с рабочего сервера:
#!/bin/bash # # Объявление переменных export IPT="iptables" # Интерфейс который смотрит в интернет export WAN=ens18 export WAN_IP=95.169.190.64 # lxc сеть export LAN1=virbr0 export LAN1_IP_RANGE=10.1.1.1/24 # Очистка всех цепочек iptables $IPT -F $IPT -F -t nat $IPT -F -t mangle $IPT -X $IPT -t nat -X $IPT -t mangle -X # Установим политики по умолчанию для трафика, не соответствующего ни одному из правил $IPT -P INPUT DROP $IPT -P OUTPUT DROP $IPT -P FORWARD DROP # разрешаем локальный траффик для loopback $IPT -A INPUT -i lo -j ACCEPT $IPT -A OUTPUT -o lo -j ACCEPT # Разрешаем исходящие соединения самого сервера $IPT -A OUTPUT -o $WAN -j ACCEPT # Разрешаем доступ из lxc наружу и обратно $IPT -A FORWARD -i $LAN1 -o $WAN -j ACCEPT $IPT -A FORWARD -i $WAN -o $LAN1 -j ACCEPT $IPT -A INPUT -i $LAN1 -j ACCEPT $IPT -A OUTPUT -o $LAN1 -j ACCEPT # Включаем NAT $IPT -t nat -A POSTROUTING -o $WAN -s $LAN1_IP_RANGE -j MASQUERADE # Пробрасываем порты в контейнер lxc_centos $IPT -t nat -A PREROUTING -p tcp --dport 23543 -i $ -j DNAT --to 10.1.1.2:22 $IPT -t nat -A PREROUTING -p tcp --dport 80 -i $ -j DNAT --to 10.1.1.2:80 $IPT -t nat -A PREROUTING -p tcp --dport 443 -i $ -j DNAT --to 10.1.1.2:443 # Состояние ESTABLISHED говорит о том, что это не первый пакет в соединении. # Пропускать все уже инициированные соединения, а также дочерние от них $IPT -A INPUT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT # Пропускать новые, а так же уже инициированные и их дочерние соединения $IPT -A OUTPUT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT # Разрешить форвардинг для уже инициированных и их дочерних соединений $IPT -A FORWARD -p all -m state --state ESTABLISHED,RELATED -j ACCEPT # Включаем фрагментацию пакетов. Необходимо из за разных значений MTU $IPT -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu # Отбрасывать все пакеты, которые не могут быть идентифицированы # и поэтому не могут иметь определенного статуса. $IPT -A INPUT -m state --state INVALID -j DROP $IPT -A FORWARD -m state --state INVALID -j DROP # Приводит к связыванию системных ресурсов, так что реальный # обмен данными становится не возможным, обрубаем $IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP $IPT -A OUTPUT -p tcp ! --syn -m state --state NEW -j DROP # Рзрешаем пинги $IPT -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT $IPT -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT $IPT -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT $IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # Открываем порт для ssh $IPT -A INPUT -i $WAN -p tcp --dport 22 -j ACCEPT # Записываем правила /sbin/iptables-save > /etc/sysconfig/iptables
Не забудьте поменять имена сетевых интерфейсов и ip адреса. Я не рекомендую настраивать фаервол, если у вас нет доступа к консоли сервера. Так вы можете потерять управление сервером.
В моем примере показан проброс порта ssh, http и https внутрь контейнера с ip адресом 10.1.1.2. Дальше в примерах я его создам.
Делаем скрипт /etc/iptables.sh исполняемым:
Запускаем iptables и добавляем в автозагрузку:
# systemctl start iptables.service # systemctl enable iptables.service
Выполняем скрипт с правилами: