Подтвердить что ты не робот

Общая библиотека в контейнерах

Для двух процессов A и B обе библиотеки используют libc.so, libc.so загружается в память только один раз. Это нормальная ситуация, когда A и B работают на одном и том же хосте и с теми же rootfs.

Когда дело доходит до контейнера, если A и B работают в разных контейнерах, A и B используют одну и ту же область памяти?

например

imageA

- libc.so

- програм

imageB

- libc.so

- programB

мы используем chroot для запуска A и B в разных rootfs. Оба libc.so одинаковы. Будет ли libc.so загружаться в память дважды?

4b9b3361

Ответ 1

На самом деле процессы A и B, которые используют общую библиотеку libc.so, могут совместно использовать одну и ту же память. В некотором роде неинтуитивно это зависит от того, какой драйвер хранилища докеров вы используете. Если вы используете драйвер хранилища, который может выставлять файлы разделяемой библиотеки как исходящие из одного и того же устройства /inode, когда они находятся на одном уровне докеров, они будут использовать одни и те же страницы кэша виртуальной памяти. При использовании драйверов памяти aufs, overlay или overlay2 тогда ваши общие библиотеки будут обмениваться памятью, но при использовании каких-либо других драйверов памяти они не будут.

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

Ответ 2

Вы можете выяснить, используют ли .so в разных контейнерах одну и ту же физическую память, сравнив физические адреса процессов (/proc/pid/pagemap) из двух разных контейнеров, как видно на хосте.

# ps -ef | grep java | grep -v grep | awk '{ print $2 }'
3906
4018
# sudo pmap -X 3906 | grep -e "Address" -e "libpthread"
     Address Perm   Offset Device     Inode    Size   Rss   Pss Referenced Anonymous LazyFree ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
7f97d9249000 r-xp 00000000  fd:00 135202206     104   104    52        104         0        0              0              0               0    0       0      0 libpthread-2.27.so
# sudo pmap -X 4018 | grep -e "Address" -e "libpthread"
     Address Perm   Offset Device     Inode    Size   Rss   Pss Referenced Anonymous LazyFree ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
7fce739e1000 r-xp 00000000  fd:00 135202206     104   104    52        104         0        0              0              0               0    0       0      0 libpthread-2.27.so
# virt_to_phys_user 3906 0x7f97d9249000
0x59940000
# virt_to_phys_user 4018 0x7fce739e1000
0x59940000

Здесь 3906 и 4018 - идентификатор процесса на хосте двух экземпляров Java-приложения, работающего в двух разных контейнерах. Я использовал virt_to_phys_user, которая является простой программой 'c', чтобы выгрузить физическую память с заданным pid и виртуальную память из этой ссылки. Обратите внимание, что физический адрес одинаков для обоих процессов выше. Также обратите внимание, что оба экземпляра имеют одинаковый адрес inode, а Pss указывает, что эти страницы являются общими.

Однако, как упоминалось в предыдущем ответе, это поведение зависит от используемого драйвера хранилища. Я вижу, что это работает на docker-ce в Ubuntu 18.04 и podman на RHEL8 (overlay2 и overlay fs соответственно), но не работает на RHEL 7.5 с devicemapper.

Ответ 3

Они не будут использовать одну и ту же область RAM; что цель виртуализации (с контейнерами) в любом случае - для изоляции ресурсов (памяти) и других. Для получения дополнительной информации см. Группы памяти. Хорошая ссылка здесь с анимация.