Mock Docker для реализации простого контейнера, менее 200 строк кода (включая пустые строки, комментарии, обработку исключений), это не хвастовство B. Контейнерная технология — это почти встроенный модуль ядра Linux, и мы можем делать многое, просто вызывая API. Конечно, если учесть различные коммерческие и политические факторы, это вырастет в объем кода масштаба Docker.
Чтобы украсть шутку в кругу друзей: разница между маленькой компанией и большой компанией заключается в том, что, взяв в качестве примера убийство свиней, небольшая компания находит свинью и прямо зарубает ее до смерти. Крупные компании должны сначала сделать набор клеток для отлова свиней, затем сделать набор процессов для заточки ножей, а затем изобрести набор ножевых методов (инженеры обычно долго спорят о ножевых методах) для умерщвления свиней. Помимо ловли свиней, клетки для ловли свиней могут ловить и блох, а приспособления для заточки ножей могут не только точить топоры, но и кусачки для ногтей. Процесс умерщвления свиней может убить не только свиней, но и кур. Когда вы закончите, вам нужно будет только ввести приказ убить свинью. Вы не знаете, где свинья, потому что это чья-то ответственность, а код находится в какой-то директории, о которой вы не знаете; вы не знаете, где нож, потому что директория не видна и формат не удобочитаемый. Ты не знаешь, что такое нож. Теоретически эта система чрезвычайно эффективна. Над ее созданием работала группа людей. Они ничего не сделали, кроме как убивали свиней топорами. Они никогда не тестировали цыплят, а код для уничтожения блох неполный. Но все в компании считали, что убивать свиней нужно именно так. Так что все заняты каждый день, а свиньи радуются из года в год.
Итак, в этой серии статей я в основном расскажу, как найти свинью, как держать нож, не причинив себе вреда, и как приложить силу, чтобы быть более злобным, а затем устроить живое представление, чтобы заколоть свинью живьем.
задействованная технология
Для написания контейнера требуется всего две технологии — Namespace и CGroup, и эти две вещи предоставляет ядро Linux, все, что нам нужно сделать, это — вызвать его. Бессовестно украв изображение Бога Брендан Грегг.
Эта картина содержит часто упускаемую из виду деталь — контейнеры совместно используют ядро, они принадлежат нескольким процессам, запущенным в ядре одновременно, но они изолированы пространством имен, а CGroup используется для ограничения доступных ресурсов. В то время как виртуальные машины совместно используют «аппаратное обеспечение», каждая виртуальная машина имеет свою собственную независимую операционную систему. Поэтому виртуальные машины — это загрузочные и абсолютно безопасные технологии изоляции, а контейнеры — очень хрупкие и небезопасные технологии изоляции.
Пространство имен — это технология изоляции, предоставляемая ядром Linux, которое обеспечивает шесть пространств изоляции:
Ты выглядишь ошеломленным, да? Все в порядке, просто объясните это кратко.
Студенты, изучившие принципы работы операционных систем, знают (не так ли? Вы смеете смешиваться в этой отрасли?), что все процессы в ядре совместно используют ресурсы, определенные операционной системой — имя хоста, имя домена, таблицу ARP, маршрутизацию. таблица, таблица NAT, файловая система, пользователь и группа, номер процесса. Возьмем в качестве примера имя хоста, оно определяется операционной системой в пространстве памяти, поэтому процесс A может его видеть, и процесс B также может его видеть (или даже изменять его, если у него есть разрешение). Пространства имен обеспечивают метод изоляции, который позволяет каждому процессу определять «собственное имя хоста». Вы можете понять, что ядро предоставляет резервную копию текущего имени хоста для каждого процесса.Конечно, процесс может модифицировать эти данные, но эта модификация может быть применена только к себе, и другие процессы не могут ее воспринять - потому что она больше не " "Глобальный.
Люди часто спрашивают, все ли приложения могут быть контейнеризированы? Понимание пространства имен позволяет легко ответить на этот вопрос. Контейнерная технология по сути является общим ядром, поэтому любое приложение, которому необходимо модифицировать ядро, не может быть помещено в контейнер. Например, такие приложения, как LVS и OpenvSwitch, которым необходимо загружать модули ядра, нельзя превратить в контейнеры.
Hello world
Вызов Namespace очень прост и требует только одного API (да, одного, всего одного) — clone.
Он создаст новый поток (ядро не слишком различает потоки и процессы), первый параметр указывает запись кода потока, второй параметр — стек потока, третий параметр — бит флага, а четвертый параметр Указатель параметра для ввода кода.
Перечисленные выше параметры Namespace передаются через третий параметр — бит флага.
Давайте сначала проверим, правильно ли работает UTS (имя хоста), поскольку подпроцесс не включает рекурсивные вызовы, поэтому определения размера стека в 1024 байта должно быть достаточно. os.waitpid(pid, 0) в основном методе обязателен, иначе дочерний процесс завершится раньше, потому что родительский процесс завершится.
child_func — это точка входа дочернего процесса.В этом коде мы вызываем sethostname, чтобы изменить хост, а затем выполняем hostname, чтобы проверить, вступила ли модификация в силу.
libc — это мой упакованный системный вызов, очень простой.
Попробуйте:
Сначала выведите свой собственный номер процесса и номер дочернего процесса в родительском процессе, а затем выведите свой собственный номер процесса и номер родительского процесса в дочернем процессе. В дочернем процессе мы вызываем sethostname, чтобы изменить имя хоста и проверить результат вызова с именем хоста. Но эта модификация не повлияла на ядро, и мы окончательно проверили этот результат, вызвав hostname в оболочке.
иметь оболочку
Вышеупомянутое действие — это всего лишь действие по изменению имени хоста, действие небольшое и недостаточно приятное. Мы хотим иметь возможность получить оболочку в отдельном пространстве имен.
Нужно изменить только две строки кода. В родительском процессе добавляются флаги NEW_PID и NEW_IPC, а в дочернем процессе вызывается execle для выполнения bash, а через последний параметр указывается переменная среды PS1, которая указывает на подсказку.
Выполнив еще раз, мы обнаружили, что оболочка изменилась. Убедитесь, что мы находимся «внутри контейнера» по имени хоста. Введите exit, чтобы выйти из контейнера.
Не может скрыть волнение в сердце. Не волнуйтесь, волнений больше, переходим к третьему шагу — отсоединению файловой системы.
Рекомендовать группу по обмену и обучению: 478030634 В ней будут представлены видеоролики, записанные старшими архитекторами: анализ исходного кода Spring, MyBatis, Netty, принципы высокой параллелизма, высокой производительности, распределенной микросервисной архитектуры, оптимизация производительности JVM, они становятся архитекторами Необходимое тело знаний. Вы также можете получить бесплатные учебные ресурсы, которые в настоящее время приносят большую пользу:
полное разделение
Если вы наберете несколько команд top, ps, ls в оболочке из предыдущей части, то обнаружите, что она почти такая же, как и в среде «Host». Это потому, что мы не сделали самую важную часть — отсоединение файловой системы.
Docker предоставляет образы Ubuntu и CentOS, на самом деле это не образы в строгом смысле, их точное название должно быть - корневая файловая система.
Контейнеры используют общее ядро, поэтому и Ubuntu, и CentOS используют ядро хоста.Если вы посмотрите на uname в Docker, вы обнаружите, что независимо от того, какой образ, их версия ядра точно такая же, как у хоста. Следовательно, образы Docker с разными «операционными системами» на самом деле являются разными корневыми файловыми системами.
Многие люди используют rootfs BusyBox как демонстрацию того, как кокетливый человек может быть таким клише. Поэтому я использую CentOS 7 в качестве демонстрации.
Настоящая причина заключается в переключении корневого каталога в контейнере.Последующее выполнение кода будет использовать новую корневую файловую систему, а последующий код зависит от среды выполнения Python. Итак, нам нужна rootfs с Python, и CentOS 7 делает именно это. Если мы будем использовать C или Golang, такого ограничения не будет.
Вы можете найти соответствующую загрузку rootfs через Dockerfile, предоставленный CentOS, например: https://github.com/CentOS/sig-...ocker
Разархивируйте загруженный файл в каталог /tmp.
Разделение файловой системы разделено на три шага. Во-первых, мы создаем файловую систему /proc в контейнере.Многие команды Linux читают содержимое этой файловой системы (например, список процессов, отображаемый вверху); во-вторых, нам нужно сделать текущий пользователь Mapping с пользователем в контейнере, иначе он запросит недостаточные разрешения; наконец, нам нужно «переключить» корневую файловую систему через функцию pivot_root.
Не забудьте изменить основной метод, добавить к флагу три параметра и сопоставить пользователя.
Сделайте это снова.
Как и в CentOS 7, вы даже можете использовать команду yum.Конечно, поскольку мы еще не реализовали сетевую функцию, yum сообщит вам, что доступ к сети недоступен.
Выполните еще несколько файлов добавить, удалить файлы, чтобы увидеть? Вы обнаружите, что независимо от того, что вы делаете, окончательные данные будут надежно зафиксированы в /tmp/rootfs, то есть у нас нет возможности получить доступ к файлам хоста в контейнере.
Полный код: https://github.com/fireflyc/mini-docker.