Что такое контейнер? Статья для понимания трех основных технологий — Namespace, Cgroup и UnionFS.

контейнер

Что такое контейнер? Как работают контейнеры? Как контейнеры изолируют ресурсы? Почему контейнер запускается так быстро? ...Если вы любознательный ребенок, у вас возникнут подобные вопросы, когда вы будете использовать контейнер. Эта статья ответит на ваши вопросы о принципе контейнера, объяснив его три основные технологии: пространство имен Linux, группы управления (cgroups) и UnionFS (Union File System).

Linux Namespace

Пространства имен Linux — это схема изоляции ресурсов, предоставляемая ядром Linux. Ресурсы между пространствами имен не зависят друг от друга. В настоящее время в Linux доступно семь пространств имен.

Ссылаться на:full7.org/Linux/полный страх…

Namespace Flag иллюстрировать
Cgroup CLONE_NEWCGROUP Изолировать контрольные группы
IPC CLONE_NEWIPC Изоляция межпроцессного взаимодействия
Network CLONE_NEWNET Изолировать сетевые ресурсы
Mount CLONE_NEWNS Изолированная точка монтирования
PID CLONE_NEWPID ID процесса в карантине
User CLONE_NEWUSER Изолировать идентификаторы пользователей и групп пользователей
UTS CLONE_NEWUTS Изолировать информацию об имени хоста и доменном имени

КcloneСистемный вызов передается в соответствующую таблицу в приведенной выше таблице.FlagПараметры, вы можете создать соответствующее пространство имен для вновь созданного процесса. также можно использоватьsetnsСистемный вызов добавляет процесс в существующее пространство имен. Контейнеры реализуют изоляцию ресурсов с помощью технологии пространства имен.

пространства имен ограничивают, какие ресурсы может видеть контейнер.

Пример: Создать контейнер через оболочку под linux

Говорить дешево, покажи мне код.

Мы непосредственно используем пример, чтобы продемонстрировать эффект ресурсов изоляции пространства имен. Из командной строки мы можем передатьunshareКоманда для запуска нового процесса и создания для него соответствующего пространства имен. В этом примере мы перейдемunshareСоздадим исключение для нашего контейнераcgroupа такжеuserВсе пространства имен, кромеdocker run somethingПо умолчанию используется пространство имен, созданное контейнером. Этот пример опирается наdockerсреду, чтобы предоставить нам некоторое удобство настройки. Полный пример сценария находится вздесь, для всеобщего удобстваscriptreplayОглянитесь на процесс.

git clone https://github.com/DrmagicE/build-container-in-shell
cd ./build-container-in-shell
scriptreplay build_container.time build_container.his

шаг 1: подготовьте rootfs

Во-первых, нам нужно подготовить собственную корневую файловую систему для нашего контейнера — файловую систему, которая обеспечивает изолированную среду выполнения для процесса контейнера. Здесь мы напрямую экспортируемalpineЗеркалируйте как наши rootfs, выбирайте/root/containerКаталог как зеркало rootfs:

[root@drmagic container]# pwd 
/root/container
[root@drmagic container]# # 修改mount类型为private,确保后续的mount/umount不会在namespace之间传播
[root@drmagic container]# mount --make-rprivate / 
[root@drmagic container]# CID=$(docker run -d alpine true)
[root@drmagic container]# docker export $CID | tar  -xf-
[root@drmagic container]# ls # rootfs建立好啦
bin  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Шаг 2: изоляция пространства имен

[root@drmagic container]# # 使用unshare为新的shell创建命名空间
[root@drmagic container]# unshare --mount --uts --ipc --net --pid --fork /bin/bash
[root@drmagic container]# echo ? # 看看新进程的pid
1
[root@drmagic container]# hostname unshare-bash # 修改一下hostname
[root@drmagic container]# exec bash #替换bash,显现hostname修改后的效果
[root@unshare-bash container]# # hostname变化了

Благодаря описанному выше процессу мы можем видетьUTSа такжеPIDЭффект изоляции этих двух пространств имен.

Если вы используете ps на этом шаге, чтобы увидеть все процессы, результаты могут вас разочаровать — вы все равно будете видеть все процессы в системе, как будто изоляция не прошла успешно. Но это нормально, потому что ps считывает информацию из /proc.В это время /proc все еще является /proc хоста, поэтому ps все еще может видеть все процессы.

Шаг 3: Изолируйте информацию о монтировании

[root@unshare-bash container]# mount # 还是能看到host上的mount
/dev/vda2 on / type xfs (rw,relatime,attr2,inode64,noquota)
devtmpfs on /dev type devtmpfs (rw,nosuid,size=1929332k,nr_inodes=482333,mode=755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
mqueue on /dev/mqueue type mqueue (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
.....

мы обнаруживаемmountВсе еще можно получить глобальную информацию о монтировании, не так ли?mountИзоляция пространства имен не работает? нет,mountПространство имен уже действует. при создании новогоmountпространства имен, он скопирует точку монтирования родительского процесса, но последующие изменения точки монтирования пространства имен не повлияют на другие пространства имен.

Ссылаться на:full7.org/Linux/полный страх…

Модификации точек монтирования в пространстве имен не влияют на другие пространства имен при обязательном условии - Mountpropagation typeДля установки в MS_PRIVATE, поэтому в начале мы должны выполнитьmount --make-rprivate /причина

Итак, что мы видимmountИнформация — это копия родительского процесса, мы воссоздаемmountодин раз/proc, так чтоpsможет отображаться нормально.

[root@unshare-bash ~]# # 重新mount一下/proc
[root@unshare-bash ~]# mount -t proc none /proc
[root@unshare-bash ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 21:29 pts/0    00:00:00 bash
root        77     1  0 21:47 pts/0    00:00:00 ps -ef
[root@unshare-bash ~]# # 啊哈,现在我们的ps正常了!

законченный/procкреплений, так же нам нужно подчистить старые точки монтирования, поставить ихumountНа этом шаге нам нужно использоватьpivot_root(new_root,put_old)Что нужно сделать.pivot_rootпоставить токmountПереключите точку монтирования корневого каталога всех процессов (потоков) в пространстве имен наnew_root, и поместите старую корневую точку монтирования вput_oldПод содержанием. использоватьpivot_rootОсновная цель – использоватьumountНекоторые точки монтирования скопированы из родительского процесса.

full7.org/Linux/полный страх…

удовлетворитьpivot_rootНекоторые требования к параметрам требуют дополнительного монтирования привязки:

[root@unshare-bash container]# mount --bind /root/container/ /root/container/
[root@unshare-bash container]# cd /root/container/
[root@unshare-bash container]# mkdir oldroot/
[root@unshare-bash container]# pivot_root . oldroot/ 
[root@unshare-bash container]# cd /
[root@unshare-bash /]# PATH=$PATH:/bin:/sbin 
[root@unshare-bash /]# mount -t proc none /proc
[root@unshare-bash /]# ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 bash
   70 root      0:00 ps -ef
[root@unshare-bash /]# mount # 依旧能看到host上的信息
rootfs on / type rootfs (rw)
/dev/vda2 on /oldroot type xfs (rw,relatime,attr2,inode64,noquota)
devtmpfs on /oldroot/dev type devtmpfs (rw,nosuid,size=1929332k,nr_inodes=482333,mode=755)
tmpfs on /oldroot/dev/shm type tmpfs (rw,nosuid,nodev)
....
[root@unshare-bash /]# umount -a # umount全部
umount: can't unmount /: Resource busy
umount: can't unmount /oldroot: Resource busy
umount: can't unmount /: Resource busy
[root@unshare-bash /]# mount -t proc none /proc # 重新mount /proc
[root@unshare-bash /]# mount
rootfs on / type rootfs (rw)
/dev/vda2 on /oldroot type xfs (rw,relatime,attr2,inode64,noquota)  <-- oldroot 还在
/dev/vda2 on / type xfs (rw,relatime,attr2,inode64,noquota)
none on /proc type proc (rw,relatime)

можно увидетьoldrootИнформация о монтировании этого старого каталога все еще там, мы помещаем ееunmountТерять:

[root@unshare-bash /]# umount -l oldroot/ # lazy umount
[root@unshare-bash /]# mount
rootfs on / type rootfs (rw)
/dev/vda2 on / type xfs (rw,relatime,attr2,inode64,noquota)
none on /proc type proc (rw,relatime)

На этом этапе контейнер может видеть только собственную информацию о монтировании, и изоляция монтирования завершена.

Шаг 4: добавляем сеть в наш контейнер

Далее мы инициализируем сеть контейнера. использоватьveth pair, с помощьюdockerкоторый предоставилdocker0Мост соединяет контейнер и хост с сетью.

[root@unshare-bash /]# ping 8.8.8.8 # 配置网络前,网络显然是不通的
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: sendto: Network unreachable
[root@unshare-bash /]# ifconfig -a
lo        Link encap:Local Loopback
          LOOPBACK  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

Вернитесь в оболочку хоста и добавьтеveth pair:

[root@drmagic ~]# pidof unshare # 容器的pid
11363
[root@drmagic ~]# CPID=11363
[root@drmagic ~]# # 添加veth pair
[root@drmagic ~]# ip link add name h$CPID type veth peer name c$CPID
[root@drmagic ~]# # 将veth一边塞到容器里
[root@drmagic ~]# ip link set c$CPID netns $CPID
[root@drmagic ~]# # 将veth另一边挂到docker0网桥上
[root@drmagic ~]# ip link set h$CPID master docker0 up

задаватьveth pair, обратно в контейнер:

[root@unshare-bash /]# ifconfig -a # 设置完之后回来看
c11363    Link encap:Ethernet  HWaddr 1A:47:BF:B8:FB:88
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          LOOPBACK  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          
[root@unshare-bash /]# ip link set lo up
[root@unshare-bash /]# ip link set c11363 name eth0 up
[root@unshare-bash /]# # 为eth0设置一个随机的docker网段内的IP地址
[root@unshare-bash /]# ip addr add 172.17.42.3/16 dev eth0
[root@unshare-bash /]# # 配置默认路由走docker的默认网关
[root@unshare-bash /]# ip route add default via 172.17.0.1
[root@unshare-bash /]# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=43 time=17.220 ms
64 bytes from 8.8.8.8: seq=1 ttl=43 time=16.996 ms
64 bytes from 8.8.8.8: seq=2 ttl=43 time=17.099 ms
64 bytes from 8.8.8.8: seq=3 ttl=43 time=17.118 ms
^C
--- 8.8.8.8 ping statistics ---
5 packets transmitted, 4 packets received, 20% packet loss
round-trip min/avg/max = 16.996/17.108/17.220 ms

Настройка сети завершена, теперь ресурсы всего контейнера изолированы от хоста.dockerФактически контейнер создается с помощью аналогичных шагов.

Cgroups

CGROUPS, ее название происходит от контрольной группы (Control Groups), также является функцией ядра Linux, используется для ограничения, контроля и статистики ресурсов (таких как ЦП, память, дисковый ввод и т. д.).

CGROUPS используется для ограничения количества используемых ресурсов.

API cgroups реализовано в виде псевдофайловой системы, то есть пользователи могут организовывать cgroups и управлять ими через файловые операции. В большинстве систем контрольные группы автоматически монтируются в/sys/fs/cgroupПод содержанием.

Cgroups содержат разные подсистемы, каждая из которых фактически является контроллером ресурса. Проверить/sys/fs/cgroupсодержание:

$ ll /sys/fs/cgroup/
drwxr-xr-x 7 root root  0 11月 11 22:49 blkio
lrwxrwxrwx 1 root root 11 11月 11 22:49 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 11月 11 22:49 cpuacct -> cpu,cpuacct
drwxr-xr-x 6 root root  0 11月 11 22:49 cpu,cpuacct
drwxr-xr-x 4 root root  0 11月 11 22:49 cpuset
drwxr-xr-x 6 root root  0 11月 11 23:40 devices
drwxr-xr-x 4 root root  0 11月 11 22:49 freezer
drwxr-xr-x 4 root root  0 11月 11 22:49 hugetlb
drwxr-xr-x 6 root root  0 11月 11 22:49 memory
lrwxrwxrwx 1 root root 16 11月 11 22:49 net_cls -> net_cls,net_prio
drwxr-xr-x 4 root root  0 11月 11 22:49 net_cls,net_prio
lrwxrwxrwx 1 root root 16 11月 11 22:49 net_prio -> net_cls,net_prio
drwxr-xr-x 4 root root  0 11月 11 22:49 perf_event
drwxr-xr-x 6 root root  0 11月 11 22:49 pids
drwxr-xr-x 6 root root  0 11月 11 22:49 systemd

КромеsystemdКроме того, каждый каталог в приведенном выше каталоге представляет собой подсистему.Из приведенного выше рисунка видно, что он содержит связанные с процессором (cpu, cpuacct, cpuset), связанные с памятью (memory), связанные с вводом-выводом блочного устройства (blkio), связанные с сетью (net_cls, net_prio) и другие подсистемы.

Cgroups используют древовидные иерархические отношения для управления различными подсистемами, и каждая подсистема имеет свою собственную древовидную структуру. Узел в дереве представляет собой группу процессов (или потоков), а иерархические отношения различных подсистем не зависят друг от друга. Например, иерархическая структура подсистемы процессора и подсистемы памяти может быть разной:

cpu/                                
├── batch
│   ├── bitcoins
│   │   └── 52   // <-- 进程ID
│   └── hadoop
│       ├── 109
│       └── 88
└── docker
    ├── container1
    │   ├── 1
    │   ├── 2
    │   └── 3
    └── container2
        └── 4
        
memory/
├── 109
├── 52
├── 88
└── docker
    ├── container1
    │   ├── 1
    │   ├── 2
    │   └── 3
    └── container2
        └── 4

Добавить процесс в группу очень просто, достаточно зайти в соответствующий каталог группыtasksФайл можно записать в Pid:echo “pid” > tasks.

если вы используетеdockerзапустите контейнер, затемdockerбудет создан в каждом каталоге подсистемы для контейнераdocker/$container_idсодержание.这样cgroups就能对该容器的资源进行管理和限制了。

memory cgroup

memoryКонтрольная группа — это контрольная группа, которая управляет памятью, и ее две основные функции:

  • Статистика использования памяти текущей группой.
  • Ограничьте использование памяти текущей группой.

статистика

memorycgroups используют страницы памяти в качестве единицы для отслеживания и подсчета использования памяти каждой группой. Взяв в качестве примера docker, используйте следующие команды, чтобы запустить контейнер nginx и прочитать использование памяти контейнера:

$ container_id=$(docker run -d nginx)d
$ cat /sys/fs/cgroup/memory/docker/$container_id/memory.usage_in_bytes
2666496

Поскольку статистика представлена ​​в единицах страницы, результат статистики может быть кратным размеру страницы (обычно 4096).

ограничение

memorycgroups может ограничивать использование памяти всей группой (по умолчанию без ограничений). Есть две ограничивающие способности:

  • жесткий лимит.
  • Мягкий лимит.

Если объем памяти превысит жесткий предел, сработает OOM-killer текущей группы, чтобы убить процесс.

Если вы не хотите, чтобы процесс был убит, вы можете отключить OOM -killer текущей группы:
echo 1 > memory.oom_control

По сравнению с жестким способом жесткого ограничения, мягкое ограничение не приведет к принудительному завершению процесса, а мягкое ограничение будет работать только при нехватке системной памяти. Когда памяти недостаточно, cgroup сделает все возможное, чтобы ограничить память каждой группы ниже мягкого предела, чтобы обеспечить общую доступность системы.

все еще подниматьdockerНапример, мы используем следующие команды, чтобы установить жесткое ограничение и мягкое ограничение контейнера nginx на 100M и 50M соответственно, и вы можете увидеть изменения в соответствующих файлах cgroup:

$ container_id=$(docker run -d -m 100m --memory-reservation 50m nginx)
$ cat /sys/fs/cgroup/memory/docker/$container_id/memory.limit_in_bytes
104857600  <-- 100m
$ cat /sys/fs/cgroup/memory/docker/$container_id/memory.soft_limit_in_bytes
52428800 <-- 50m

cpuа такжеcpuacct cgroup

cpuа такжеcpusetЭто две контрольные группы, но обычно эти две контрольные группы будут смонтированы в одном каталоге:

...
lrwxrwxrwx 1 root root 11 11月 11 22:49 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 11月 11 22:49 cpuacct -> cpu,cpuacct
drwxr-xr-x 6 root root  0 11月 11 22:49 cpu,cpuacct
...

cpuа такжеcpuacctОсновные функции в сочетании с (CPU Accounting):

  • Статистика по использованию ЦП текущей группы.
  • Ограничьте возможность группы использовать ЦП (влияя на политику планирования).

статистика

Статистическая функция в основном состоит изcpuacctУкажите, например, общее время ЦП, затраченное на чтение текущей группы:

$ cat cpuacct.usage
1196687732756025  //单位是ns

ограничение

Влияя на поведение планирования планировщика, можно ограничить возможности использования ЦП текущей группы, что также является принципом ограничения контейнером количества ядер ЦП.cpucgroups может управлять поведением планирования следующих двух планировщиков:

  • Полностью честный планировщик (CFS) Планировщик, основанный на полностью честном алгоритме.
  • Планировщик реального времени (RT) Планировщик, основанный на алгоритме планирования в реальном времени.

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

$ cat cpu.cfs_period_us
100000
$ cat cpu.cfs_quota_us
-1

cpu.cfs_period_us

Указывает период планирования в микросекундах (мкс). Указывает, как часто выполнять планирование, по умолчанию 100 мс (100000 мкс).

Чем дольше период планирования, тем больше пропускная способность ЦП для выполнения задач и соответствующее увеличение задержки. Напротив, Чем короче период планирования, тем меньше задержка, но при этом снижается и пропускная способность ЦП (потому что много времени тратится на «бесполезное» переключение процессов).

cpu.cfs_quota_us

Указывает, что в течение одного цикла планирования (т. е.cpu.cfs_period_usустановленное время), всем процессам в текущей группе разрешеноодин ЦПОбщая продолжительность выполнения в микросекундах (мкс). По умолчанию -1, т.е. без ограничений.

Предполагая, что текущая группа хочет в полной мере использовать ресурсы двухъядерного процессора, вы можете установить:

  • cpu.cfs_quota_us = 200000
  • cpu.cfs_period_us= 100000

Точно так же, если мы хотим разрешить использование только 0,5 ядра для текущей группы, то:

  • cpu.cfs_quota_us = 50000
  • cpu.cfs_period_us= 100000

cpu.cfs_quota_us/cpu.cfs_period_us = количество ядер процессора, выделенных для текущей группы

когда мы используемdockerПри указании количества ядер контейнера вы фактически настраиваетеcpu.cfs_quota_usпараметры файла.

cpuset cgroup

cpusetИспользуется редко, при погоне за экстремальной производительностью можно использовать для привязки ядер, привязки узлов памяти NUMA и других функций:

  • cpuset.cpusИспользуется для указания того, какие процессоры могут использоваться текущей группой.
  • cpuset.memsИспользуется для указания того, какие узлы NUMA могут использоваться текущей группой.

Архитектура NUMA (неоднородный доступ к памяти) разделяет модуль ЦП на несколько узлов NUMA.Каждый модуль ЦП состоит из нескольких ЦП (например, 4) и имеет независимую локальную память и слоты ввода-вывода, рот и т. д. Скорость доступа ЦП к памяти этого узла NUMA очень высока, что эквивалентно слою кеша над памятью.

NUMA не входит в диапазон, обсуждаемый здесь (я тоже не понял), заинтересованные друзья, пожалуйста, проверьте соответствующую информацию самостоятельно.

Например, при просмотре информации о ЦП и узлах NUMA на моем локальном компьютере есть:

$ lscpu
...
CPU(s):                2
On-line CPU(s) list:   0,1  <- 双核cpu
....
NUMA 节点:         1  <- 只有一个numa节点
....
NUMA 节点0 CPU:    0,1 <- numa节点上的CPU
....

мы смотримcpusetСоответствующие файлы в каталоге:

$ cat cpuset.cpus
0-1  
$ cat cpuset.mems
0 

То есть контрольная группа по умолчанию разрешает текущей группе использовать все узлы ЦП и памяти NUMA. пройти черезdockerКоманда может реализовать функцию привязки ядра и узла NUMA:

Ссылаться на:docs.docker.com/engine/ref Э…

blkio cgroup

blkiocgroup — это cgroup, связанная с вводом-выводом блочного устройства.blkioДве основные функции cgroups:

  • Статистика использования каждого блочного устройства текущей группой
  • Ограничить использование блочных устройств текущей группой

статистика

blkioСтатистика использования всех блочных устройств текущей группой.Статистические измерения следующие:read,write,sync,asyncчетыре. Взяв в качестве примера статистику байтов, два связанных с ней файла:blkio.io_service_bytesа такжеblkio.throttle.io_service_bytes:

$ cat blkio.io_service_bytes
Total 0
$ cat blkio.throttle.io_service_bytes
253:0 Read 0
253:0 Write 8192
253:0 Sync 8192
253:0 Async 0
253:0 Total 8192
Total 8192

blkio.io_service_bytesОн учитывает только использование блочных устройств, которые используют планировщик CFQ, в большинстве случаев это 0. Для общей статистики это в основном зависит отblkio.throttle.*файл в начале.

ограничение

blkioИспользование блочных устройств группой может быть ограничено, что предусматривает две стратегии ограничения:

  • Политика планирования веса: она действительна только в том случае, если блочное устройство использует политику планирования CFQ (полностью справедливая организация очереди).Установив весовой размер для группы, возможность группы использовать блочное устройство ограничивается.
  • Регулирование ввода-вывода: эта политика ограничивает возможность группы использовать блочное устройство, устанавливая верхний предел скорости ввода-вывода блочного устройства.

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

Вы можете просмотреть политику планирования блочного устройства с помощью следующей команды (замените vda на блочное устройство для просмотра):
cat /sys/block/vda/queue/scheduler
[mq-deadline] kyber none
Если вы видите cfq, действует политика планирования веса.

В более общем примере ограничения политики ввода-вывода следующие четыре файла для ограничения количества байтов в секунду и чтения операций ввода-вывода:

  • blkio.throttle.read_bps_device
  • blkio.throttle.read_iops_deviceЧтение количества операций в секунду
  • blkio.throttle.write_bps_deviceбайтов, записываемых в секунду
  • blkio.throttle.write_iops_deviceОпераций записи в секунду

Запишите «старший: младший байт в секунду/количество раз» в четыре файла выше, чтобы установить максимальное количество байтов/операций чтения и записи для соответствующего устройства.

Major и Minor — это старший и младший номера устройств, соответствующие блочным устройствам, к которым можно получить доступ черезls -lt /dev/Проверьте соответствующий номер блочного устройства на хосте.

кblkio.throttle.write_bps_deviceНапример, ограничьте скорость записи текущей группы на устройство 253:0 (/dev/vda), чтобы она не превышала 10 МБ/с:

$ echo "253:0 10485760" > blkio.throttle.write_bps_device

Быть осторожнымblkioОграничение состоит в том, что в операции ввода-вывода блочного устройства обычная операция записи сначала проходит через кеш страничного кэша, а затем асинхронно сбрасывается на диск, и скорость записи в кеш страничного кэша не пострадает. .blkioпределы. Если вы хотите увидеть эффект ограничения тока, используйте прямой ввод-вывод, например:

$ dd if=/dev/zero of=test bs=10M count=5 oflag=direct
5+0 records in
5+0 records out
52428800 bytes (52 MB, 50 MiB) copied, 4.94449 s, 10.6 MB/s

Видно, что скорость записи после ограничения тока составляет примерно 10,6 МБ/с, что не так уж и плохо.

net_clsа такжеnet_prio cgroup

net_clsа такжеnet_prioдве cgroup, связанные с сетью:

  • net_clsМаркируя сетевые пакеты идентификатором класса (classid), он позволяет программам управления трафиком (TC: Traffic Controller) идентифицировать пакеты, сгенерированные из определенных контрольных групп.
  • net_prioМожно установить приоритет использования каждого сетевого интерфейса.

мы не можем пройти напрямуюnet_clsдобиться подобногоblkioТаким образом, если вы хотите получить функцию ограничения скорости, вам нужно использовать TC для ее достижения - путемnet_clsОн отвечает за маркировку пакетов данных, а TC будет ограничивать поток после идентификации.

devices cgroup

devicescgroups используются для управления групповым доступом к устройствам, включаяread,writeа такжеmknodразрешения.

Просмотр под контрольной группойdevices.listФайл может получить разрешения устройства текущей группы:

$ cat devices.list
c 1:5 rwm
b *:* m

Формат каждой строки следующий: type (тип устройства) major:minor access (полномочия доступа).

Существует три типа оборудования:

  • aПредставляет все устройства, включая символьные и блочные устройства.
  • bПредставляет блочное устройство.
  • cПредставляет символьное устройство.

мажор: минор вblkioбыл введен в , его можно использовать здесь*в качестве подстановочного знака для представления всех чисел, например.*:*Указывает все номера устройств.

Разрешение на доступ — это строка, содержащая одну или несколько букв, обозначающих разные разрешения:

  • rразрешение на чтение.
  • wразрешение на запись.
  • mРазрешение на создание файлов устройств.

Удалите некоторые специальные виртуальные устройства,dockerПо умолчанию контейнеру запрещен доступ к любому устройству на хосте. в состоянии пройти--devicesпараметр, чтобы добавить разрешения устройства в контейнер, или использовать--privilegedПараметр включает привилегированный режим, используйте--privilegedКонтейнеры, запущенные с параметрами, получат все разрешения на всех устройствах на хосте:

Ссылаться на:docs.docker.com/engine/ref Э…

$ container_id=$(docker run -d --privileged nginx)
$ cat /sys/fs/cgroup/devices/docker/$container_id/devices.list
a *:* rwm  <--- 所有设备的所有权限

Ссылка на открытое виртуальное устройство по умолчанию:GitHub.com/container/…

freezer cgroup

freezercgroups может приостанавливать и возобновлять процессы внутри группы.freezer.stateФайл записывает текущее фактическое состояние:

  • THAWEDОттаявшее состояние (нормальное рабочее состояние).
  • FREEZINGЗамораживание.
  • FROZENЗамороженный (подвешенный).

Кfreezer.stateЗапись в середине может изменить состояние текущей группы, разрешена только записьFROZEN(замороженный) илиTHAWED(восстанавливаться).

docker pauseэто использоватьfreezerЧтобы приостановить и возобновить работу контейнера:

$ container_id=$(docker run -d nginx)
$ docker pause $container_id
$ cat /sys/fs/cgroup/freezer/docker/$container_id/freezer.state
FROZEN  <--- 冻结了

pids cgroup

pidsCgroups используются для ограничения количества задач (задач, представляющих потоки или процессы) в группе. Чтобы включить ограничение задач, перейдите кpids.maxЗапишите максимально допустимое число в файл или напишите строку «max» для неограниченного (по умолчанию). чтениемpids.currentфайл, вы можете получить количество всех задач в текущей группе.

докер может пройти--pids-limitпараметр для ограничения количества процессов в контейнере:

$ container_id=$(docker run -d --pids-limit 3 nginx)
$ cat /sys/fs/cgroup/pids/docker/$container_id/pids.max
3

UnionFS

UnionFSЭто файловая система, которая позволяет объединять несколько каталогов в логический каталог, содержащий все содержимое этих каталогов и обеспечивающий унифицированное представление внешнего мира.
Например, предположим, что нам нужно обновить содержимое компакт-диска, но этот компакт-диск недоступен для записи.В это время мы можем смонтировать компакт-диск с другой доступной для записи директорией какUnionFS. Когда мы обновляем файл, содержимое записывается в доступный для записи каталог, как если бы содержимое компакт-диска было обновлено.

образ контейнера (image) обеспечивает «статическое представление» контейнера, а образ содержит различные файлы, от которых зависит запуск контейнера. Мы можем изменить эти файлы в работающем контейнере, не затрагивая само изображение. Это связано с тем, что каталог внутри контейнера и каталог изображений объединены в один.UnionFS, С точки зрения контейнера образ подобен компакт-диску (не для записи), изменение контейнера в каталоге будет записано только в собственный каталог контейнера и не повлияет на содержимое образа.

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

Copy-on-write

Скорость запуска контейнера очень высокая (даже при большом размере образа), что связано с использованием технологии копирования при записи (COW, copy-on-write). Когда мы запускаем контейнер, нам не нужно копировать файлы всего образа. Контейнер напрямую ссылается на файлы в образе. Любая операция чтения может быть напрямую прочитана из образа. Когда происходит операция записи, нам нужно только скопируйте файл в образ. Соответствующие файлы в образе копируются в доступный для записи слой контейнера и записываются в доступный для записи слой.

dockerВ документации есть подробные введения и примеры COW.docs.docker.com/storage/stones…

OverlayFS

UnionFSСуществует множество реализацийdockerТакже можно настроить различные типыstorage driver, более знакомые:overlay2,aufs,devicemapper.

Ссылаться на:docs.docker.com/storage/stones…

вместе сOverlayFSбыл включен в основную ветку ядра Linux,overlay2все более и более широко используемым, он также сталdockerрекомендуемыеstorage driver. Эта статья занимаетOverlayFSа такжеoverlay2Пример того, как контейнеры могут извлечь выгоду изUnionFSи копирование при записи.

устанавливатьOverlayFS:

$ mount -t overlay overlay -o lowerdir=lower1:lower2:lower3...,upperdir=upper,workdir=work  merged

Ссылаться на:full7.org/Linux/полный страх…(Поиск наложения)

Приведенная выше команда будетmergedкаталог, смонтированный какOverlayFSlowerdirЭто слой только для чтения (зеркальный слой), позволяющийupperdirЭто пишетный слой (контейнерный слой). Это означает, что когда мыmergedКогда каталог записывается в файл, файл записывается вupperdir. отmergedПри чтении файла из каталога, если файл находится вupperdirне существует, то следующий слой изlowerdirнайти в.

workdirОн используется системой для выполнения некоторой подготовительной работы перед монтированием. требуется пустой каталог, за которым следуетupperdirв той же файловой системе.

Визуализируйте на примереOverlayFSПоведение чтения и записи:

$ mkdir lower upper work merged
$ echo "lowerdir" > lower/test
$ echo "upper" > upper/test # upper跟lower都有相同的文件test
$ echo "lowerdir" > lower/lower # lower才有的文件
$ mount -t overlay overlay -o lowerdir=lower,upperdir=upper,workdir=work  merged
$ ls merged/ # mount后看到lower跟upper的统一视图
lower  test
$ cat merged/test
upper # upper, lower都有该文件,读upper的文件
$ cat merged/lower # upper没有该文件,读lower文件
lowerdir
$ echo "write something" >> merged/test
$ cat upper/test # 向merged的写入仅影响upper层
upper
write something
$ cat lower/test
lowerdir

использоватьdocker runПосле создания контейнераdockerбудет контейнерmountОдинOverlayFS:

$ docker run -itd alpine /bin/sh
$ mount | grep overlay2
overlay on /var/lib/docker/overlay2/a2a37f61c515f641dbaee62cf948817696ae838834fd62cf9395483ef19f2f55/merged type overlay
(rw,relatime,
lowerdir=/var/lib/docker/overlay2/l/RALFTJC6S7NV4INMLE5G2DUYVM:
         /var/lib/docker/overlay2/l/WQJ3RXIAJMUHQWBH7DMCM56PNK,
upperdir=/var/lib/docker/overlay2/a2a37f61c515f641dbaee62cf948817696ae838834fd62cf9395483ef19f2f55/diff,
workdir=/var/lib/docker/overlay2/a2a37f61c515f641dbaee62cf948817696ae838834fd62cf9395483ef19f2f55/work)

dockerбудет отражать каждыйlayerдобавлено для того, чтобыlowerdirв, будетupperdirУстановите доступный для записи слой контейнера.

когда мы используемdocker pull imageкогда,dockerКаталоги для каждого слоя только для чтения в зеркале созданы и выполняютсяdocker run, в основном просто создайте доступные для записи слои контейнера и смонтируйте их какOverlayFSВот и все. Таким образом, даже если образ большой, запуск контейнера все равно происходит очень быстро.

когда вы используетеdocker pullПри вытягивании зеркала оно должно было появитьсяAlready existsидентификация.

docker pull xxxx
...
68ced04f60ab: Already exists <---
e6edbc456071: Pull complete
...

docker pullЕсли содержимое этого слоя уже существует локально, его не нужно извлекать. Различные изображения будут использовать один и тот же слой в/var/lib/docker/overlay2Будет сохранен только один соответствующий каталог файлов, что уменьшит нагрузку на диск.

В документации докера есть подробное введение в рабочий процесс overlay2:docs.docker.com/storage/stones…

Другие ссылки

класс документа
full7.org/Linux/полный страх…
woohoo.kernel.org/doc/doc U-дверь… access.RedHat.com/document ATI…
Android.Google source.com/kernel/com…

класс блога
www.sel.zju.edu.cn/?p=573
Добавь V и ты готов.ru/blog/2019/1…
woo woo woo.info Q. талант/статья/нет я…

видео
Cgroups, namespaces, and beyond: what are containers made from?:
Woohoo.YouTube.com/watch?V=SK5…
(Видео сокровищ, сильный толчок)