n1ro°
RU

Текст и данные · Инструкция

Docker cpu-shares vs cpus: как работают ограничения CPU

Docker cpu-shares vs cpus — это сравнение двух разных механизмов, а не двух способов записать одно и то же.

Редакция N1RO · Проверено

Короткий ответ

`--cpus` задаёт верхний предел вычислительного времени контейнера, а `--cpu-shares` — относительный вес при конкуренции за CPU. Shares почти не ограничивают контейнер, когда процессор свободен; `--cpus=0.5` ограничивает его примерно половиной одного CPU.

Как работает --cpu-shares и почему это не процент

Docker описывает `--cpu-shares` как относительный вес CPU. Историческое базовое значение — 1024: если два нагруженных контейнера имеют 1024 и 512 shares, первый получает примерно вдвое больше процессорного времени в ситуации реальной конкуренции. Но это не означает фиксированные 66% и 33% всегда. Если второй контейнер почти ничего не делает, первый может использовать свободный процессор полностью.

Именно поэтому shares плохо подходят как защита хоста от runaway-процесса. Контейнер с низким весом способен загрузить CPU, когда конкурентов нет. Зато механизм полезен для мягкого приоритета: например, интерактивный API получает больший вес, чем ночная обработка, но фоновой задаче не запрещается ускориться, если сервер простаивает. Значения нужно сравнивать между контейнерами на одном хосте, а не воспринимать как абсолютные единицы производительности.

Числовой пример помогает не путать вес и потолок. Пусть два постоянно загруженных контейнера конкурируют за один доступный CPU и имеют shares 1024 и 512. При прочих равных первый получает примерно вдвое больший относительный вес, пока процессор действительно занят обоими. Но если второй контейнер почти ничего не делает, первый может использовать свободный CPU целиком: shares не превращаются в жёсткий потолок 66%. Именно поэтому по одному контейнеру на пустом хосте разницу между 1024 и 512 можно вообще не заметить — приоритет проявляется в конкуренции.

Совет: Shares имеет смысл тестировать под одновременной нагрузкой нескольких контейнеров. Тест одного контейнера на пустом хосте почти ничего не показывает о реальном приоритете.

Как работает --cpus и что означает дробное значение

`--cpus` — более прямой интерфейс к CPU quota. Docker принимает дробное число: `--cpus=0.5` разрешает контейнеру в среднем использовать половину вычислительного времени одного логического CPU, `--cpus=2` — до эквивалента двух CPU. Это не закрепляет процесс за конкретными ядрами; для привязки существует отдельный `--cpuset-cpus`.

Под капотом лимит связан с периодом и квотой планировщика. Docker также предоставляет низкоуровневые `--cpu-period` и `--cpu-quota`, но для большинства обычных контейнеров `--cpus` проще и понятнее. Жёсткий потолок полезен, когда несколько арендаторов делят один сервер, когда нельзя позволить batch-задаче забрать весь хост или когда вы хотите воспроизвести ограниченную среду в тестах.

Совет: Если приложение параллельное, `--cpus=2` не означает, что оно всегда работает ровно на двух конкретных ядрах. Для этого нужен `--cpuset-cpus`, который решает другую задачу.

Как выбрать параметр для своего контейнера

  1. Если нужен абсолютный потолок нагрузки, начните с `--cpus` и задайте число CPU по требованиям сервиса.
  2. Если нужен только приоритет между соседними контейнерами, используйте `--cpu-shares` и относительные веса.
  3. Для критичного сервиса можно сочетать механизмы: установить верхний лимит и одновременно дать больший относительный вес при конкуренции.
  4. Нагрузите одновременно все основные сервисы и смотрите latency, throughput и throttling, а не только средний CPU в `docker stats`.
  5. Если приложение само определяет число worker-потоков по числу CPU, проверьте, корректно ли оно видит cgroup-лимит; при необходимости задайте workers явно.
  6. После изменения лимитов повторите тест пикового трафика: слишком маленькая quota может создавать очередь даже при наличии свободных ядер на хосте.

Предупреждение: Ограничение CPU — не оптимизация приложения. Если сервис упирается в один поток или делает лишнюю работу, увеличение quota лишь маскирует проблему.

Можно ли менять лимиты у уже запущенного контейнера

Docker поддерживает изменение ряда ресурсных настроек через `docker update`, включая `--cpu-shares` и `--cpus`. Это удобно для эксперимента на тестовом окружении или для временной коррекции без пересоздания контейнера. После изменения обязательно проверьте, что фактическая конфигурация совпадает с ожидаемой, а сервис не стал нестабилен из-за throttling.

Для воспроизводимой инфраструктуры ручной `docker update` не должен оставаться единственным источником правды. Зафиксируйте лимиты в Compose, шаблоне запуска или другой декларативной конфигурации. Иначе после пересоздания контейнера настройки исчезнут. В Compose лимиты CPU могут задаваться в соответствующих полях ресурсов; конкретный синтаксис зависит от того, какой режим Compose и deploy specification вы используете.

`docker update` позволяет менять `--cpu-shares` и `--cpus` у уже запущенного контейнера, поэтому параметры можно подбирать без пересоздания сервиса. Меняйте один лимит за раз, создавайте одинаковую нагрузку и сравнивайте latency, throughput и признаки throttling. Не делайте вывод только по мгновенному значению CPU в `top`: короткие пики и паузы приложения легко искажают картину. После теста перенесите подтверждённые значения в Compose или другой декларативный конфиг, иначе следующий recreate вернёт исходные параметры запуска.

Важно: Ручное изменение полезно как диагностика, но после теста перенесите подтверждённые значения в конфигурацию проекта и version control.

Типичные ошибки при сравнении cpu-shares и cpus

Первая ошибка — считать 512 shares «половиной CPU». Это только половина веса относительно контейнера с 1024 shares при одновременной конкуренции. Вторая — задавать `--cpus=1` и ожидать, что процесс будет постоянно видеть 100% одного физического ядра: планировщик может распределять разрешённое CPU-время между логическими ядрами.

Третья ошибка — забывать о Docker Desktop. На Windows и macOS контейнеры работают внутри Linux VM; сначала сама VM получает ограниченное число CPU, а уже внутри неё действуют контейнерные лимиты. Если Docker Desktop разрешено использовать четыре CPU, контейнер с `--cpus=8` не получит восемь физических CPU хоста.

Наконец, не оценивайте результат только по «проценту CPU». Смотрите, как изменились время ответа, длительность задач, количество throttled periods и загрузка соседних сервисов. Ограничение считается удачным, когда оно решает задачу изоляции и не ломает SLA приложения.

Что учитывать

Docker описывает `--cpu-shares` как относительный вес CPU. Историческое базовое значение — 1024: если два нагруженных контейнера имеют 1024 и 512 shares, первый получает примерно вдвое больше процессорного времени в ситуации реальной конкуренции. Но это не означает фиксированные 66% и 33% всегда. Если второй контейнер почти ничего не делает, первый может использовать свободный процессор полностью. Именно поэтому shares плохо подходят как защита хоста от runaway-процесса. Контейнер с низким…

Источники и проверка

Фактическая часть сверена по первичным источникам (в т.ч. Running containers). Пример и формулировки — редакция N1RO на 2026-09-22.