50% снижение производительности Docker при интенсивном использовании процессора

Я новичок в использовании докеров или любых контейнеров, поэтому, пожалуйста, будьте осторожны, если я пропустил что-то очевидное, что все уже знают. Я искал везде, где только мог подумать, но не видел, чтобы эта проблема решалась.

Я пытаюсь оценить затраты на производительность при запуске теста в докере и обнаружил удивительно большие различия, которые для меня не имеют смысла. Я создал простой образ Docker с этим Dockerfile:

FROM ubuntu:18.04

RUN apt -y -q update && apt -y -q install python3 vim strace linux-tools-common \
        linux-tools-4.15.0-74-generic linux-cloud-tools-4.15.0-74-generic

ADD . /workspace
WORKDIR /workspace

И у меня есть простой скрипт на Python для тестирования:

$ cat cpu-test.py
#!/usr/bin/env python3

import math
from time import time

N = range(10)
N_i = range(1_000)
N_j = range(1_000)
x = 1

start = time()
for _ in N:
    for i in N_i:
        for j in N_j:
            x += -1**j * math.sqrt(i)/max(j,2)
stop = time()
print(stop-start)

а затем я сравниваю его нормальный запуск с запуском в контейнере:

$ ./cpu-test.py
4.077672481536865
$ docker run -it --rm cpu:test ./cpu-test.py
6.113868236541748
$

Я исследовал это с помощью perf, что привело меня к открытию, что мне нужен --privileged для запуска perf внутри докера, но затем разрыв в производительности исчез:

$ docker run -it --rm --privileged cpu:test ./cpu-test.py
4.1469762325286865
$ 

Ищу что-нибудь связанное с докером и --privileged в основном приводит к списку причин, по которым я не должен использовать привилегии из соображений безопасности, не нашел ничего о серьезном влиянии на производительность обычного кода.

Используя perf для сравнения запусков с / без привилегий, они выглядят совершенно иначе:

С привилегией, топ-5 в отчете о производительности:

     7.26%  docker   docker            [.] runtime.mapassign_faststr
     6.21%  docker   docker            [.] runtime.mapaccess2
     6.12%  docker   [kernel]          [k] 0xffffffff880015e0
     5.37%  docker   [kernel]          [k] 0xffffffff87faac87
     4.92%  docker   docker            [.] runtime.retake

при работе без привилегий приводит к:

    11.11%  docker   docker            [.] runtime.evacuate_faststr
     8.14%  docker   docker            [.] runtime.scanobject
     7.18%  docker   docker            [.] runtime.mallocgc
     5.10%  docker   docker            [.] runtime.mapassign
     4.44%  docker   docker            [.] runtime.growslice

Я не знаю, имеет ли это значение, поскольку я совершенно не знаком с кодом среды выполнения докера.

Я делаю что-то неправильно? Или мне нужно повернуть какую-то специальную ручку?

Спасибо

4 ответа

Флаг seccomp:unconfined при добавлении к docker run Команда улучшает производительность программы Python. seccomp- это функция ядра Linux, которая может использоваться для ограничения действий, доступных внутри контейнера, путем разрешения или запрета выполнения определенных системных вызовов хосту. Это сокращает доступ контейнера к хосту и, в терминологии безопасности, помогает уменьшитьattack surfaceконтейнера. По умолчаниюseccomp профиль отключает 44 системных вызова для запущенных контейнеров, включая perf_event_open и когда вы добавляете флаг --security-opt seccomp:unconfined все системные вызовы включены для работающего контейнера.

С момента добавления seccomp:unconfined помогает программе Python работать с почти 1,5-2-кратной скоростью, первый пункт анализа - это посмотреть на strace output и посмотрите, не замедляют ли какие-либо системные вызовы работу, если этот флаг не добавлен.

  • Выход с --security-opt seccomp:unconfined флаг
strace -c -f -S name docker run -it --rm --security-opt seccomp:unconfined cpu:test ./cpu-test.py

5.4090752601623535
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  2.00    0.000194          32         6         6 access
  0.11    0.000011          11         1           arch_prctl
  0.33    0.000032          11         3           brk
  0.00    0.000000           0         1           capget
  0.10    0.000010           1        16           clone
  0.64    0.000062           4        17           close
  0.00    0.000000           0         5         2 connect
  0.00    0.000000           0         1           epoll_create1
  0.00    0.000000           0        14         2 epoll_ctl
  0.22    0.000021           0        62           epoll_pwait
  0.29    0.000028          28         1           execve
  0.00    0.000000           0         8           fcntl
  0.67    0.000065           8         8           fstat
 68.87    0.006687          22       310        24 futex
  0.02    0.000002           2         1           getgid
  0.00    0.000000           0         3           getpeername
  0.00    0.000000           0         2           getpid
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         3           getsockname
  0.10    0.000010           1        17           gettid
  0.02    0.000002           1         2           getuid
  0.00    0.000000           0         5         1 ioctl
  0.00    0.000000           0         1           lseek
  5.83    0.000566           7        84           mmap
  2.12    0.000206           5        39           mprotect
  0.35    0.000034           2        14           munmap
  0.00    0.000000           0        12         9 newfstatat
  1.43    0.000139          10        14           openat
  0.13    0.000013          13         1           prlimit64
 10.21    0.000991          10       102           pselect6
  0.55    0.000053           2        34        10 read
  0.00    0.000000           0         1           readlinkat
  3.14    0.000305           3       120           rt_sigaction
  0.36    0.000035           1        53           rt_sigprocmask
  0.04    0.000004           4         1           sched_getaffinity
  2.04    0.000198           5        42           sched_yield
  0.18    0.000017           1        17           set_robust_list
  0.03    0.000003           3         1           set_tid_address
  0.00    0.000000           0         3           setsockopt
  0.22    0.000021           1        34           sigaltstack
  0.00    0.000000           0         5           socket
  0.00    0.000000           0         7           write
------ ----------- ----------- --------- --------- ----------------
100.00    0.009709                  1072        54 total
  • Выход без --security-opt seccomp:unconfined флаг
strace -c -f -S name docker run -it --rm cpu:test ./cpu-test.py

8.161764860153198
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.08    0.000033           6         6         6 access
  0.04    0.000015          15         1           arch_prctl
  0.02    0.000007           2         3           brk
  0.00    0.000000           0         1           capget
  0.22    0.000087           6        15           clone
  0.26    0.000102           6        17           close
  0.04    0.000015           3         5         2 connect
  0.00    0.000000           0         1           epoll_create1
  0.14    0.000054           4        14         2 epoll_ctl
  2.31    0.000916          23        40           epoll_pwait
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         8           fcntl
  0.07    0.000027           3         8           fstat
 72.00    0.028580          99       290        21 futex
  0.01    0.000002           2         1           getgid
  0.01    0.000002           1         3           getpeername
  0.00    0.000000           0         2           getpid
  0.00    0.000000           0         1           getrandom
  0.01    0.000002           1         3           getsockname
  0.10    0.000039           2        16           gettid
  0.01    0.000002           1         2           getuid
  0.01    0.000005           1         5         1 ioctl
  0.00    0.000000           0         1           lseek
  1.33    0.000529           7        80           mmap
  0.72    0.000284           8        37           mprotect
  0.31    0.000125           8        15           munmap
  0.07    0.000026           2        12         9 newfstatat
  0.20    0.000080           6        14           openat
  0.01    0.000003           3         1           prlimit64
 20.04    0.007954          42       189           pselect6
  0.21    0.000085           3        34        10 read
  0.00    0.000000           0         1           readlinkat
  0.46    0.000182           2       120           rt_sigaction
  0.52    0.000207           4        50           rt_sigprocmask
  0.01    0.000004           4         1           sched_getaffinity
  0.27    0.000108           5        20           sched_yield
  0.11    0.000045           3        16           set_robust_list
  0.01    0.000003           3         1           set_tid_address
  0.01    0.000002           1         3           setsockopt
  0.32    0.000127           4        32           sigaltstack
  0.02    0.000008           2         5           socket
  0.09    0.000035           5         7           write
------ ----------- ----------- --------- --------- ----------------
100.00    0.039695                  1082        51 total

Пока ничего существенного. Итак, следующее, что нужно было проанализировать, - это сама программа Python.

Все приведенные ниже команды для получения профилей времени выполнения были запущены 5 раз, и была выбрана одна из этого пробного пространства. Времена были очень минимальными.

Запуск контейнеров в фоновом режиме, а затем exec-заправка в контейнер,

  • Результат выполнения профиля в программе Python, запущенной внутри контейнера с --security-opt seccomp:unconfined флаг
docker exec -it cpu-test-seccomp bash
root@133453c7ccc6:/workspace# python3 -m cProfile ./cpu-test.py 

7.339433908462524
         20000069 function calls in 7.340 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:103(release)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:143(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:147(__enter__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:151(__exit__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:157(_get_module_lock)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:176(cb)
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:211(_call_with_frames_removed)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:222(_verbose_message)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:232(_requires_builtin_wrapper)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:307(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:311(__enter__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:318(__exit__)
        4    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:321(<genexpr>)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:369(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:416(parent)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:424(has_location)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:433(spec_from_loader)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:504(_init_module_attrs)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:564(module_from_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:58(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:651(_load_unlocked)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:707(find_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:728(create_module)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:736(exec_module)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:753(is_package)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:78(acquire)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:843(__enter__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:847(__exit__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:870(_find_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:936(_find_and_load_unlocked)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:966(_find_and_load)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:997(_handle_fromlist)
        1    5.540    5.540    7.340    7.340 cpu-test.py:3(<module>)
        3    0.000    0.000    0.000    0.000 {built-in method _imp.acquire_lock}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.create_builtin}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.exec_builtin}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.is_builtin}
        3    0.000    0.000    0.000    0.000 {built-in method _imp.release_lock}
        2    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
        2    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.any}
        1    0.000    0.000    7.340    7.340 {built-in method builtins.exec}
        4    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
        5    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
 10000000    1.228    0.000    1.228    0.000 {built-in method builtins.max}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
 10000000    0.571    0.000    0.571    0.000 {built-in method math.sqrt}
        2    0.000    0.000    0.000    0.000 {built-in method time.time}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        2    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
        2    0.000    0.000    0.000    0.000 {method 'rpartition' of 'str' objects}
  • Результат выполнения профиля в программе Python, запущенной внутри контейнера без --security-opt флаг
docker exec -it cpu-test-no-seccomp bash
root@500724539bd0:/workspace# python3 -m cProfile ./cpu-test.py 
11.848757982254028
         20000069 function calls in 11.849 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:103(release)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:143(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:147(__enter__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:151(__exit__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:157(_get_module_lock)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:176(cb)
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:211(_call_with_frames_removed)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:222(_verbose_message)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:232(_requires_builtin_wrapper)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:307(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:311(__enter__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:318(__exit__)
        4    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:321(<genexpr>)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:369(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:416(parent)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:424(has_location)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:433(spec_from_loader)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:504(_init_module_attrs)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:564(module_from_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:58(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:651(_load_unlocked)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:707(find_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:728(create_module)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:736(exec_module)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:753(is_package)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:78(acquire)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:843(__enter__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:847(__exit__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:870(_find_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:936(_find_and_load_unlocked)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:966(_find_and_load)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:997(_handle_fromlist)
        1    8.654    8.654   11.849   11.849 cpu-test.py:3(<module>)
        3    0.000    0.000    0.000    0.000 {built-in method _imp.acquire_lock}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.create_builtin}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.exec_builtin}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.is_builtin}
        3    0.000    0.000    0.000    0.000 {built-in method _imp.release_lock}
        2    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
        2    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.any}
        1    0.000    0.000   11.849   11.849 {built-in method builtins.exec}
        4    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
        5    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
 10000000    2.155    0.000    2.155    0.000 {built-in method builtins.max}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
 10000000    1.039    0.000    1.039    0.000 {built-in method math.sqrt}
        2    0.000    0.000    0.000    0.000 {built-in method time.time}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        2    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
        2    0.000    0.000    0.000    0.000 {method 'rpartition' of 'str' objects}

Тайминги в обоих случаях немного завышены из-за накладных расходов на профилирование. Но здесь заметны две вещи -

  • Встроенный math.sqrt а также builtins.max функции показывают разницу во времени выполнения почти в 1,5-2 раза, и эта разница становится заметной, поскольку эти функции вызываются 10000000 раз.

  • Получающееся в результате общее время выполнения будет медленнее без флага, как видно на builtins.exec функции и время их выполнения.

Чтобы лучше понять это явление, math.sqrt так же хорошо как maxфункции были удалены. Строка ниже вcpu-test.py-

x += -1**j * math.sqrt(i)/max(j,2)

был изменен на -

x += 1

и import math Линия также была удалена, тем самым уменьшив накладные расходы на import заявление.

  • С --security-opt seccomp:unconfined
root@133453c7ccc6:/workspace# python3 -m cProfile ./cpu-test.py 
0.7199039459228516
         8 function calls in 0.720 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:997(_handle_fromlist)
        1    0.720    0.720    0.720    0.720 cpu-test.py:4(<module>)
        1    0.000    0.000    0.720    0.720 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        2    0.000    0.000    0.000    0.000 {built-in method time.time}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


  • Без --security-opt seccomp:unconfined
root@500724539bd0:/workspace# python3 -m cProfile ./cpu-test.py
1.0778992176055908
         8 function calls in 1.078 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:997(_handle_fromlist)
        1    1.078    1.078    1.078    1.078 cpu-test.py:4(<module>)
        1    0.000    0.000    1.078    1.078 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        2    0.000    0.000    0.000    0.000 {built-in method time.time}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Также делаю perf record -e ./cpu-test.py после запуска контейнера с --privileged flags, а затем perf report, мы можем видеть -

Samples: 20K of event 'cycles:ppp', Event count (approx.): 17551108136                                                                                                                                      
Overhead  Command  Shared Object      Symbol                                                                                                                                                                
  14.56%  python3  python3.6          [.] 0x0000000000181c0b
  11.65%  python3  python3.6          [.] _PyEval_EvalFrameDefault
   5.75%  python3  python3.6          [.] PyDict_GetItem
   3.43%  python3  python3.6          [.] PyDict_SetItem
   1.69%  python3  python3.6          [.] 0x0000000000181e45
   1.68%  python3  python3.6          [.] 0x0000000000181c23
   1.59%  python3  python3.6          [.] 0x00000000001705c9
   1.54%  python3  python3.6          [.] 0x0000000000181a88
   1.54%  python3  python3.6          [.] 0x0000000000181bfa
   1.48%  python3  python3.6          [.] 0x0000000000181c56
   1.48%  python3  python3.6          [.] 0x0000000000181c71
   1.42%  python3  python3.6          [.] 0x0000000000181c42
   1.37%  python3  python3.6          [.] 0x0000000000181c8a
   1.28%  python3  python3.6          [.] 0x0000000000181c01
   1.09%  python3  python3.6          [.] _PyObject_GC_New
   0.96%  python3  python3.6          [.] PyNumber_Multiply
   0.63%  python3  python3.6          [.] PyLong_AsDouble
   0.59%  python3  python3.6          [.] PyObject_GetAttr
   0.57%  python3  python3.6          [.] 0x00000000000c4df9
   0.57%  python3  python3.6          [.] 0x0000000000165808
   0.56%  python3  python3.6          [.] PyObject_RichCompare
   0.53%  python3  python3.6          [.] PyNumber_Negative

Большую часть времени проводят в _PyEval_EvalFrameDefault, что является верным признаком того, что большую часть времени интерпретатор тратит на выполнение байтового кода.

Было бы справедливо предположить, что добавление --security-opt seccomp:unconfinedускоряет интерпретатор при выполнении байтового кода. Для этого потребуется немного покопаться вPython внутренности.

Обратите внимание, что вывод в дизассемблированном виде одинаков в обоих случаях, работая с--seccomp:unconfined а также с использованием профиля seccomp по умолчанию.

Как описал , Юсуке Эндох в своем блогерезкое замедление работы языков сценариев, таких как python, perl и ruby, работающих под docker (и containerd) с профилем seccomp по умолчанию, по-видимому, вызвано защитой от уязвимости ядра под названием Speculative Store Bypass.

Снижение риска подавляет косвенное предсказание ветвления (называемое STIBP). По это делает данным phoronix,большую часть кода намного медленнее . Снижение риска добавлено в ядре 4.20, но было быстро отключено по умолчанию из-за влияния на производительность.

Чтобы узнать, включено ли смягчение для вашего ядра, запустите:

      $ cat /sys/devices/system/cpu/vulnerabilities/spec_store_bypass
Mitigation: Speculative Store Bypass disabled via prctl and seccomp

Оказывается, запуск программы с помощью seccomp обеспечивает печально известное смягчение последствий STIBP, делая некоторые рабочие нагрузки, такие как языки сценариев, в два раза медленнее.

Решения проблемы (за счет безопасности) включают запуск или добавление параметров ядра, чтобы отключить соответствующее смягчение:

  • docker run --security-opt seccomp:unconfined
  • Загрузка ядра с помощью: mitigations=off
  • Загрузка ядра с помощью: spectre_v2_user=off spec_store_bypass_disable=off

Какое решение будет лучшим, полностью зависит от того, что работает в системе. Если вы полностью доверяете коду в контейнере докера, но в системе работают ненадежные виртуальные машины, вы можете выбрать --security-opt seccomp:unconfined. В противном случае я бы поддержал Линуса Торвальдса и использовал параметры ядра, чтобы отключить смягчение.

Другие возможные замедления (хотя и не столь значительные), связанные с seccomp, которые все еще могут возникнуть при запуске старого ядра / seccomp:

С seccomp 2.5, ядром Linux 5.12 и mitigiations=off Я наблюдаю более 99% собственной производительности с докером по сравнению с менее чем 80% собственной производительностью с настройками смягчения по умолчанию в Centos / Fedora.

По этой ссылке:

Когда оператор выполняет docker run --privileged, Docker разрешит доступ ко всем устройствам на хосте, а также установит некоторую конфигурацию в AppArmor или SELinux, чтобы позволить контейнеру почти такой же доступ к хосту, что и процессы, выполняющиеся вне контейнеров на хосте.. Дополнительная информация о работе с --privileged доступна в блоге Docker.

Я чувствую, что есть ограничения безопасности, которые при работе в привилегированном режиме практически отключены. Я считаю, что природа этих ограничений безопасности, как правило, приводит к снижению производительности при включении, однако эта производительность снижается для поддержания разумной безопасности. Это было бы очень заметно при выполнении задач с интенсивным использованием ЦП, как в вашем примере.

даже если этот вопрос сейчас немного старый, я все равно помог бы некоторым людям поделиться нашим решением.

Похоже, настоящая причина проблемы здесь в libseccomp2версия, установленная на вашем компьютере. Обновив его, apt-get install --only-upgrade libseccomp2, вы сможете повысить производительность своего приложения и избежать установки --security-opt seccomp:unconfined при запуске вашего контейнера.

Другие вопросы по тегам