Контейнеры нужно уметь ограничивать в ресурсах, которые им предоставляет хостовая операционная система. Научимся создавать лимиты и указывать приоритеты.
LXD предлагает различные возможности для ограничения ресурсов. Некоторые ограничения применимы к самому контейнеру: квоты ОЗУ, лимиты CPU и приоритеты I/O. Некоторые ограничения связаны с конкретным устройством типа пропускной способности I/O или лимитами дискового использования.
Как и конфигурации LXD, лимиты на ресурсы можно динамически изменять "на лету". Иногда операция может завершиться с ошибкой. К примеру, вы выставляете лимит ОЗУ ниже, чем сейчас контейнер потребляет сейчас, но в любом случае LXD будет пытаться выполнить ваше задание и доложит о неудаче.
Все лимиты могут быть унаследованы из профилей, применяемые к данному контейнеру. То есть установка limits.memory=256MB в профиле default заставит контейнеры, использующие его (как правило, все), иметь максимальный объём ОЗУ = 256 Мб.
Не поддерживается ограничение ресурсов на группу контейнеров, так как нет простого и хорошего способа реализовать подобное на существующем kernel API.
Наиболее востребованная функциональность - установить ограничение на размер файловой системы контейнера. LXD позволяет это сделать, хотя это сложнее выполнить, чем это кажется на первый взгляд. В Linux нет возможности установить квоты на каталог (path-based quotas), а большинство файловых систем оперируют квотами на пользователя или группу, что мало полезно для контейнеров.
Это означает, что в данный момент LXD поддерживает только лимиты для диска, только если используется ZFS или btrfs. Возможно реализовать данный функционал и для LVM, но тут всё в большей степени зависит от файловой системы, так как не все ФС позволяют онлайн увеличение (online growth) или уменьшение (online shrink) своего размера.
Когда речь заходит о ЦПУ, то поддерживаются 4 вещи:
Можно комбинировать первый режим с одним из двух последних. Запросить ограничить количество ЦПУ и дополнительно ограничить процессорное время.
Кроме того, имеется регулятор приоритета, который используется для подсказок планировщику (scheduler) кто побеждает когда система загружена и 2 контейнера борются за один и тот же ресурс.
Лимиты про память звучат просто - дайте мне X Мб ОЗУ! Поддерживаются запросы с помощью процентов - дайте мне 10% ОЗУ хоста! Так же можете реализовать следующее: выбрать включён или не включён swap на уровне каждого контейнера и если он включён, то указать контейнеру чтобы выгружал память в swap в первую очередь.
Ограничения память по умолчанию жёсткие (hard). То есть когда кончится память, то OOM Killer (out of memory killer) начнёт резвиться с вашими процессами. В качестве альтернативы вы можете установить мягкие (soft) ограничения, тогда позволено будет потреблять сколько хотите пока кто-то так же не потребует памяти. Вам не будет выделено памяти до тех пор пока не отдадите обратно ниже своего лимита или пока хост не получит память от других контейнеров.
Поддерживаются две вещи:
Самое странное напоследок. Вам покажется, что всё просто, но есть масса случаев, в которых всё будет работать не так как вы задумали.
Поддержка ограничений I/O для блочных устройств подобна вышеописанному ограничению сетевых интерфейсов. Вы можете установить лимиты IOPS или байт/сек на чтение и запись. Указать приоритет блочного I/O, который подсказывает планировщику I/O о предпочтениях.
Странность появляется от того, как и где эти лимиты применяются. К сожалению, основная особенность реализации ограничений в том, что они применяются ко всему блочному устройству. Это означает, что вы не можете установить ограничение ввода-вывода на раздел и тем более на путь в ФС. Это так же означает, что при использовании ZFS или btrfs, которые могут использовать несколько блочных устройств, мы гарантированно не можем знать какое блочное устройство обслуживает данный путь. Это означает, что, вполне возможно, контейнер может иметь множество записей про блочные устройства (bind-mount или прямые mount), которые ссылаются на тот же нижележащий диск.
И вот тут всё становится действительно странным. Для того, чтобы всё работало, LXD имеет логику, выясняющая какие блочные устройства связаны с данным путём. Опрашиваются ZFS и btrfs инструменты и рекурсивно распутываются петлевые (loop) устройства. Логика хоть и не идеальна, но даёт множество блочных устройств, к которым нужно применить лимиты. LXD, получив все пути, попадает в реально странную область. Среднее значение лимитов, установленное вами для каждого блочного устройства, применяется к ним. Это означает, что "в среднем" вы будете получать правильные значения в контейнере, но это так же означает, что вы не сможете иметь /fast и /slow каталоги на том же физическом диске и с различающимися лимитами скорости. LXD позволит установить значения, но в реальности скорость будет как среднее из этих двух значений.
Большинство ограничений, описанных выше, применяются с помощью Linux cgroups API. Сетевые лимиты применяются через старый, добрый tc.
LXD при старте определяет какие cgroup есть в ядре хоста и использует только доступные. Если какие-либо cgroup отсутствуют, то вам будет выведено сообщение и помещено в журнал. В Ubuntu 16.04 всё доступно по умолчанию, за исключением учёта swap, требующая от вас указания swapaccount=1 параметру ядра системы.
Все лимиты применяются непосредственно к контейнеру или к одному из его профилей.
Ко всему в пределах контейнера - lxc config set CONTAINER KEY VALUE
Ко всему в пределах данного профиля - lxc profile set PROFILE KEY VALUE
Можно более тонко указать ограничения:
для конкретного устройства контейнера - lxc config device set CONTAINER DEVICE KEY VALUE
для конкретного устройства в профиле - lxc profile device set CONTAINER DEVICE KEY VALUE
Полный список опций конфигурации, типы устройств и ключи для них доступны в документации.
Лимит для контейнера только 2 ЦПУ - lxc config set my-container limits.cpu 2
Указываем использовать конкретные ядра - lxc config set my-container limits.cpu 1,3
Более сложный пример, с использованием диапазонов - lxc config set my-container limits.cpu 0-3,7-11
Ограничения применяются на лету и это подтверждает пример:
lxc exec zerotier -- cat /proc/cpuinfo | grep ^proces
processor : 0
processor : 1
processor : 2
processor : 3
lxc config set zerotier limits.cpu 2
lxc exec zerotier -- cat /proc/cpuinfo | grep ^proces
processor : 0
processor : 1
Обратите внимание, чтобы избежать запутывания userspace, lxcfs упорядочивает /proc/cpuinfo таким образом, чтобы не было промежутков-окон (gaps).
Как и всё в LXD, ограничения могут применяться из профиля
lxc exec snappy -- cat /proc/cpuinfo | grep ^proces
processor : 0
processor : 1
processor : 2
processor : 3
lxc profile set default limits.cpu 3
lxc exec snappy -- cat /proc/cpuinfo | grep ^proces
processor : 0
processor : 1
processor : 2
Указываем лимиты процессорного времени в 10% от общего - lxc config set my-container limits.cpu.allowance 10%
Жёстко нарезаем процессорное время - lxc config set my-container limits.cpu.allowance 25ms/200ms
Уменьшаем приоритет контейнера до минимума - lxc config set my-container limits.cpu.priority 0
Просто ограничиваем предел ОЗУ - lxc config set my-container limits.memory 256MB
Поддерживаются суффиксы kB, MB, GB, TB, PB и EB.
Отключить swap для контейнера (включён по умолчанию) - lxc config set my-container limits.memory.swap false
Объяснить ядру, что приоритетнее вытеснение памяти в swap - lxc config set my-container limits.memory.swap.priority 0
Переключаем лимиты из hard в soft - lxc config set my-container limits.memory.enforce soft
В отличие от процессора и памяти, ограничения диска и ввода-вывода применяются к конкретному физическому устройству. Устанавливаем квоту (требуется btrfs и ZFS) - lxc config device set my-container root size 20GB
Пример
lxc exec zerotier -- df -h /
Filesystem Size Used Avail Use% Mounted on encrypted/lxd/containers/zerotier 179G 542M 178G 1% /
lxc config device set zerotier root size 20GB
lxc exec zerotier -- df -h /
Filesystem Size Used Avail Use% Mounted on encrypted/lxd/containers/zerotier 20G 542M 20G 3% /
Скорость указываем так
lxc config device set my-container limits.read 30MB
lxc config device set my-container limits.write 10MB
Можно в IOPS
lxc config device set my-container limits.read 20Iops
lxc config device set my-container limits.write 10Iops
На загруженной системе для увеличения приоритета I/O на максимум - lxc config set my-container limits.disk.priority 10
Пример
lxc exec zerotier -- wget speedtest.newark.linode.com/100MB-newark.bin -O /dev/null
--2016-03-26 22:17:34-- speedtest.newark.linode.com/100MB-newark.bin Resolving speedtest.newark.linode.com (speedtest.newark.linode.com)... 50.116.57.237, 2600:3c03::4b Connecting to speedtest.newark.linode.com (speedtest.newark.linode.com)|50.116.57.237|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 104857600 (100M) [application/octet-stream] Saving to: '/dev/null' /dev/null 100%[===================>] 100.00M 58.7MB/s in 1.7s 2016-03-26 22:17:36 (58.7 MB/s) - '/dev/null' saved [104857600/104857600]
lxc profile device set default eth0 limits.ingress 100Mbit
lxc profile device set default eth0 limits.egress 100Mbit
lxc exec zerotier -- wget speedtest.newark.linode.com/100MB-newark.bin -O /dev/null
--2016-03-26 22:17:47-- speedtest.newark.linode.com/100MB-newark.bin Resolving speedtest.newark.linode.com (speedtest.newark.linode.com)... 50.116.57.237, 2600:3c03::4b Connecting to speedtest.newark.linode.com (speedtest.newark.linode.com)|50.116.57.237|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 104857600 (100M) [application/octet-stream] Saving to: '/dev/null' /dev/null 100%[===================>] 100.00M 11.4MB/s in 8.8s 2016-03-26 22:17:56 (11.4 MB/s) - '/dev/null' saved [104857600/104857600]
Выставляем приоритет - lxc config set my-container limits.network.priority 5
LXD API позволяет получить текущее потребление ресурсов контейнером:
lxc info zerotier
Name: zerotier Architecture: x86_64 Created: 2016/02/20 20:01 UTC Status: Running Type: persistent Profiles: default Pid: 29258 Ips: eth0: inet 172.17.0.101 eth0: inet6 2607:f2c0:f00f:2700:216:3eff:feec:65a8 eth0: inet6 fe80::216:3eff:feec:65a8 lo: inet 127.0.0.1 lo: inet6 ::1 lxcbr0: inet 10.0.3.1 lxcbr0: inet6 fe80::f0bd:55ff:feee:97a2 zt0: inet 29.17.181.59 zt0: inet6 fd80:56c2:e21c:0:199:9379:e711:b3e1 zt0: inet6 fe80::79:e7ff:fe0d:5123 Resources: Processes: 33 Disk usage: root: 808.07MB Memory usage: Memory (current): 106.79MB Memory (peak): 195.51MB Swap (current): 124.00kB Swap (peak): 124.00kB Network usage: lxcbr0: Bytes received: 0 bytes Bytes sent: 570 bytes Packets received: 0 Packets sent: 0 zt0: Bytes received: 1.10MB Bytes sent: 806 bytes Packets received: 10957 Packets sent: 10957 eth0: Bytes received: 99.35MB Bytes sent: 5.88MB Packets received: 64481 Packets sent: 64481 lo: Bytes received: 9.57kB Bytes sent: 9.57kB Packets received: 81 Packets sent: 81 Snapshots: zerotier/blah (taken at 2016/03/08 23:55 UTC) (stateless)
Команда LXD проделала многомесячную работу над созданием языка, позволяющего легко описать ваши ограничения. Задача была создать лёгкий и в тоже время мощный язык, позволяющий указать вашу специфику. Указание лимитов на лету и наследование через профиля дают вам мощный инструмент для управления нагрузкой без пагубного влияния на работающие службы.
Оглавление цикла статей про LXD 2.0.
Предыдущая статья LXD 2.0: Ваш первый LXD контейнер [3/12].
Следующая статья LXD 2.0: Управление образами [5/12].
Главная
Новости
Ворох бумаг
Видео Linux
Игры в Linux
Безопасность
Статьи об Astra Linux
Статьи о FreeBSD
Статьи об Ubuntu
Статьи о Snappy
Статьи об Ubuntu Phone
Статьи о Kubuntu
Статьи о Xubuntu
Статьи о Lubuntu
Статьи об Open Source
Карта сайта
1С под Linux. Ускорение Ubuntu. 21 пример iptables. Цикл статей о Ceph. Убунту в дикой среде. Ubuntu Linux на SSD. Ubuntu для блондинок. Поддержка железа в Linux. BTSync на службе у админа. Андроид программы в Ubuntu. Прокидывание портов для p2p. Анти СПАМ в Postfix. http://taxcom-center.ru/ отчетность сдача электронной отчетности.