Что такое контейнер? Как работают контейнеры? Как контейнеры изолируют ресурсы? Почему контейнер запускается так быстро? ...Если вы любознательный ребенок, у вас возникнут подобные вопросы, когда вы будете использовать контейнер. Эта статья ответит на ваши вопросы о принципе контейнера, объяснив его три основные технологии: пространство имен 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
Некоторые точки монтирования скопированы из родительского процесса.
удовлетворить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
Контрольная группа — это контрольная группа, которая управляет памятью, и ее две основные функции:
- Статистика использования памяти текущей группой.
- Ограничьте использование памяти текущей группой.
статистика
memory
cgroups используют страницы памяти в качестве единицы для отслеживания и подсчета использования памяти каждой группой.
Взяв в качестве примера docker, используйте следующие команды, чтобы запустить контейнер nginx и прочитать использование памяти контейнера:
$ container_id=$(docker run -d nginx)d
$ cat /sys/fs/cgroup/memory/docker/$container_id/memory.usage_in_bytes
2666496
Поскольку статистика представлена в единицах страницы, результат статистики может быть кратным размеру страницы (обычно 4096).
ограничение
memory
cgroups может ограничивать использование памяти всей группой (по умолчанию без ограничений). Есть две ограничивающие способности:
- жесткий лимит.
- Мягкий лимит.
Если объем памяти превысит жесткий предел, сработает 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
ограничение
Влияя на поведение планирования планировщика, можно ограничить возможности использования ЦП текущей группы, что также является принципом ограничения контейнером количества ядер ЦП.cpu
cgroups может управлять поведением планирования следующих двух планировщиков:
- Полностью честный планировщик (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
blkio
cgroup — это 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
devices
cgroups используются для управления групповым доступом к устройствам, включая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
freezer
cgroups может приостанавливать и возобновлять процессы внутри группы.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
pids
Cgroups используются для ограничения количества задач (задач, представляющих потоки или процессы) в группе. Чтобы включить ограничение задач, перейдите к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
каталог, смонтированный какOverlayFS
,вlowerdir
Это слой только для чтения (зеркальный слой), позволяющий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…
(Видео сокровищ, сильный толчок)