docker run --ulimit cpu=10 не убивает процесс Java после истечения времени ожидания

Я хочу убедиться, что процесс будет убит через 10 секунд процессорного времени. Команда запуска Docker принимает флаг --ulimit cpu=10, который должен это делать.

Однако, когда я запускаю команду java, используя это, параметр ulimit игнорируется. Процесс Java с бесконечным циклом продолжается даже через 10 секунд (на самом деле в течение нескольких минут, пока я его не убью). Вот команда, которую я использовал для тестирования.

docker run --rm -i -v /usr/local/src:/classes --ulimit cpu=10 java:8 \
java -cp /classes/ InfiniteLoop

Вместо прямого вызова java, если я запускаю bash, а затем запускаю java c, он работает, как и ожидалось.

docker run --rm -i -v /usr/local/src:/classes --ulimit cpu=10 java:8 \
bash -c 'date; java -cp /classes/ InfiniteLoop'

Почему вызов Java-программы напрямую не учитывает параметр ulimit?

Редактировать 1:

$ docker --version
Docker version 1.9.1, build a34a1d5

Java-программа InfiniteLoop.java

import java.util.*;

class InfiniteLoop {
  public static void main(String[] args) throws Exception {
    for (long i = 0; i < 1000_000_000_000L; i++) {
      if (i % 1_000_000_000 == 0) {
        System.out.println(new Date() + ", i = " + i);
      }
    }
  }
}

Изменить 2: следующее также не работает. То есть в bash выполняется только java.

docker run --rm -i -v /usr/local/src:/classes --ulimit cpu=10 java:8 \
bash -c 'java -cp /classes/ InfiniteLoop'

Но добавление любой команды noop или ':' работает. Или даже произвольное слово, которое печатает «команда не найдена», также работает.

docker run --rm -i -v /usr/local/src:/classes --ulimit cpu=10 java:8 \
bash -c ':; java -cp /classes/ InfiniteLoop'

и это тоже работает.

docker run --rm -i -v /usr/local/src:/classes --ulimit cpu=10 java:8 \
bash -c 'ArbirtraryCommandNotFound; java -cp /classes/ InfiniteLoop'

Правка 3. Аналогично использованию оператора no-op (:), вызов процесса со временем также приводит к завершению процесса сразу после превышения времени ЦП.

docker run --rm -i -v /usr/local/src:/classes --ulimit cpu=10 java:8 \
bash -c 'time java -cp /classes/ InfiniteLoop'

person JackDaniels    schedule 27.11.2016    source источник
comment
Это выглядит подозрительно похоже на то, о чем сообщалось в GitHub ранее в этом году: github.com/ докер/докер/проблемы/1905   -  person Michael Hausenblas    schedule 27.11.2016
comment
Потому что это то же самое, и я до сих пор не получил ответа. Было бы здорово, если бы вы знали ответ и могли бы помочь мне понять.   -  person JackDaniels    schedule 27.11.2016
comment
Мне трудно воспроизвести его, так как я не знаю, какую версию Docker вы используете, и у меня нет доступа к вашим исходным файлам Java.   -  person Michael Hausenblas    schedule 27.11.2016
comment
Добавлен исходный код java, версия докера и т. д. Еще одна вещь, которую я обнаружил, в команде bash, если я добавляю какие-либо другие команды перед java, тогда ulimit работает, в противном случае это не так.   -  person JackDaniels    schedule 27.11.2016
comment
если вы запустите top, он должен указать, сколько времени процессора занял ваш процесс Java. Я полагаю, что бесконечный цикл, печатающий дату, не привязывает процессор и, вероятно, потребует гораздо больше времени, чем 10 секунд, чтобы получить 10 секунд времени процессора.   -  person programmerq    schedule 27.11.2016
comment
@programmerq Я проверил с помощью top. Программа постоянно занимала 90+% ЦП, и столбец TIME показывал более 50 секунд, пока я не убил процесс. Это также не объясняет, почему запуск без операции перед вызовом java работает.   -  person JackDaniels    schedule 28.11.2016
comment
Так что я могу воспроизвести это сейчас на Docker 1.11.2, но все еще не знаю, почему. Буду копать, пока не найду причину.   -  person Michael Hausenblas    schedule 28.11.2016
comment
@MichaelHausenblas Спасибо. Если это поможет, я вижу такое же поведение даже при запуске программ на C++. Итак, это не было чем-то специфичным для java   -  person JackDaniels    schedule 28.11.2016
comment
@JackDaniels ага! это полезная информация, спасибо! Сейчас я исследую github.com/mhausenblas/cinf, чтобы выяснить, происходит ли что-то смешное.   -  person Michael Hausenblas    schedule 28.11.2016


Ответы (1)


После некоторого экспериментирования я перечитал исходный вопрос, а также принял во внимание тот факт, что он независимо от типа запускаемой программы, то есть Java, C++ и т. д.: причина, по которой она работает в одном случае (при вызове с bash -c), а не при непосредственном вызове, заключается в том, что ulimit является встроенная команда bash и документы для docker run не совсем понятно.

person Michael Hausenblas    schedule 28.11.2016
comment
Спасибо. Означает ли это, что ulimit никогда не будет работать при запуске любых программ, кроме bash? Это также не объясняет, почему «bash -c» также работает только тогда, когда уже есть две команды (даже если первая недопустимая команда)? - person JackDaniels; 02.12.2016
comment
Да, ulimit работает только с bash, но вы можете использовать cgroups в качестве универсального решения. - person Michael Hausenblas; 02.12.2016
comment
с cgroups я могу указать только cpu_quota для cpu_period, я хочу указать верхний предел общего использования процессора. Кроме того, я могу понять, почему ulimit будет работать только в bash, но даже в bash он не работает все время. Он работает, только если есть как минимум 2 команды, даже если дополнительная команда недействительна или вызывается со временем. - person JackDaniels; 03.12.2016
comment
В документации указано: cpu.cfs_quota_us: общее доступное время выполнения в течение периода (в микросекундах) cpu.cfs_period_us: длина периода (в микросекундах) Когда квота превышается, процесс дросселируется, а не уничтожается. (Тогда как при настройке процессора он убивается.) - person JackDaniels; 03.12.2016
comment
Вы правы. ОК, я также проверил другие документы cgroups cpu, но, похоже, единственный способ точно эмулировать ulimit — использовать системный вызов setrlimit напрямую. - person Michael Hausenblas; 04.12.2016