Русский
Русский
English
Статистика
Реклама

Containerd

Docker is deprecated и как теперь быть?

08.12.2020 14:22:23 | Автор: admin

Kubernetes объявил Docker устаревшим и планирует прекратить его использование примерно через год, в версии 1.22 или 1.23. Эта новость вызвала много вопросов и непонимания. В блоге Kubernetes появилось целых две статьи, разъясняющих смысл записи в Changelog (раз и два). Если все обобщить, то для разработчиков (те, которые Dev) ничего не меняется они все так же могут продолжать использовать docker build для сборки своих контейнеров, а вот для инженеров, ответственных за эксплуатацию кластера (Ops), пришла пора разобраться и освоить несколько новых инструментов.

Но для начала давайте вернемся в 2016 год, когда Kubernetes представил Container Runtime Interface (CRI). До версии Kubernetes 1.3 kubelet умел работать только с Docker, а в 1.3 анонсировали поддержку rkt Container Engine (этот проект уже прекратил свое существование). При этом код, отвечающий за взаимодействие с Docker и rkt, был глубоко и широко интегрирован в исходники kubelet. Процесс добавления поддержки rkt показал, что для добавления новых container runtime необходимо хорошо разбираться в устройстве и алгоритмах работы kubelet, а результат получился очень сложным для поддержки и развития.

Поэтому решили все упростить, и добавили новую абстракцию Container Runtime Interface. Весь код, реализующий высокоуровневый интерфейс работы с Docker, был убран из kubelet, а вместо него kubelet стал использовать CRI. Но тут возникла небольшая проблемка Docker не умеет в CRI. Чтобы ее решить, в Kubernetes написали программу-прокладку между kubelet и Docker. С одной стороны она принимает запросы от kubelet через CRI, а с другой транслирует их в docker-демон.

И назвали эту программу dockershim, и вот как раз ее и хотят убрать к версии 1.23.

Возвращаемся назад, в конец 2020 года, и смотрим чего у нас новенького по сравнению с 2016 в плане развития Container Runtime Interface.

  • Проект rkt закрыт.

  • RedHat создали и всячески продвигают свой собственный движок для запуска контейнеров CRI-O.

  • Монолитный Docker разделили на containerd, dockerd и docker-cli.

В итоге у нас сейчас есть два движка для запуска контейнеров, которые умеют в CRI это containerd и cri-o. Естественно, все эти события произошли не прямо в 2020 году, но массовый интерес к ним возник именно после объявления Kubernetes о прекращении поддержки Docker.

Сборка

Давайте же разберемся, чем нам это грозит. Начнем с наиболее частого вопроса: Как же собирать образ контейнера с помощью containerd или cri-o?

И ответ очень простой: Никак. Потому что containerd и cri-o предназначены только для запуска контейнеров из готовых образов. Плюс они умеют еще несколько вещей, необходимых для эксплуатации:

  • загрузка образов из интернета;

  • просмотр информации о запущенных подах и контейнерах;

  • удаление образов, подов и контейнеров;

  • подключение внутрь контейнера (запуск внутри контейнера процесса с bash).

Но они не умеют ни собирать новый образ, ни пушить его в какой-либо registry. И как теперь быть ?

Начнем с того, что в 2015 году Docker и остальные лидеры индустрии контейнеризации основали Open Container Initiative (OCI) и опубликовали в ее рамках спецификацию формата хранения образов контейнеров. Эту спецификацию поддерживают Docker, containerd и cri-o, так что образ, собранный с помощью docker build на машине разработчика, должен без проблем запустится с помощью containerd или cri-o. И так и происходит в подавляющем большинстве случаев, но время от времени попадаются нюансы реализации. Эти нюансы, конечно, исправляются, но иногда не так быстро, как хотелось бы.

Если вы за стабильность и минимальные изменения запускайте новые кластера с containerd в качестве движка контейнеризации. А на машинах разработчиков и CI runners сборки смело оставляйте Docker.

Если вы выбрали безопасность из коробки, кровавый enterpise и платную поддержку, то наверняка используете Openshift (платформа на базе Kubernetes), в котором для запуска контейнеров применяется cri-o. А для сборки образов RedHat создала отдельную утилиту, которую назвала buildah. В отличие от Docker, этой утилите для сборки образов не нужен запущенный движок контейнеризации.

Из альтернатив можно еще посоветовать kaniko утилиту для сборки образов от Google. Она поставляется в виде образа контейнера, так что для запуска ей нужен движок контейнеризации, но для сборки уже нет.

Эксплуатация

С разработкой разобрались, теперь пора перейти к самому интересному: что делать инженеру, который зашел на узел, чтобы разобраться, почему статус узла стал NotReady, набрал привычную команду docker ps, а в ответ получил docker: command not found.

Фундаментальная проблема тут в том, что Docker изначально ориентировался на взаимодействие с человеком, и к последним версиям у него появился очень классный и удобный консольный интерфейс, а вот компоненты, реализующие CRI они by design ориентированы на взаимодействие с программой-оркестратором, а не с человеком.

Но внезапно оказалось, что человек тоже хочет взаимодействовать с CRI, и для этого была написана отдельная утилита crictl, которая представляет собой CLI-консоль к CRI-движку. То есть одна и та же утилита crictl позволяет посмотреть список контейнеров запущенных с помощью containerd или cri-o.

Очень часто встречается информация, что можно просто заменить docker на crictl и вместо docker ps набирать crictl ps. Сказка заканчивается, когда вы попробуете запустить контейнер с помощью crictl run , и внезапно оказывается, что сначала надо создать манифест для PodSandbox, а уже потом написать манифест, описывающий контейнер, который будет запущен в этом поде.

С другой стороны надо помнить, что CRI был придуман командой разработки Kubernetes и для Kubernetes, и поэтому, на мой взгляд, правильнее было бы его назвать Pod Runtime Interface.

И crictl оптимизирован для работы с контейнерами, созданными kubelet. Например, в выводе не показываются служебные PODSandbox контейнеры, а имена контейнеров показываются в более понятном виде, чем в Docker. Да и возможности по работе с CLI постоянно улучшаются.

Еще одна вещь, с которой часто возникают проблемы понимания. Многие путают docker (бинарник из пакета docker-cli) и dockerd (демон, управляющий контейнерами). Пытаются сделать crictl image save/load и внезапно оказывается, что в crictl таких команд нет. А на созданный issue авторы устало отвечают, что crictl консоль для CRI runtime, который должен только запускать контейнеры, ну еще образ скачать из registry. А про манипуляции с образами в спецификации ничего нет.

Но выход есть! Для манипуляции с образами контейнеров можно воспользоваться дополнительной утилитой skopeo, если вы используете cri-o, или утилитой ctr из комплекта containerd.

И в завершение дам ответ на идею, которая наверняка возникнет после прочтения этой статьи:

Подождите, но ведь есть containerd, с которым умеет работать kubelet и dockerd! Давайте поставим Docker (три пакета docker-cli, docker, containerd), kubelet настроим на работу с containerd напрямую, и у нас при этом останется старая добрая команда docker.

Вот только docker ps не покажет контейнеров, запущенных kubelet через CRI. Произойдет это из-за того, что containerd умеет работать в многопользовательском режиме, и docker с kubelet запускают контейнеры в различных containerd namespaces moby и k8s.io соответственно (не надо путать их с kubernetes namespaces). Посмотреть на контейнеры в разных неймспейсах можно с помощью утилиты ctr -n <ns_name> container ls.

Подробнее..

Перевод Недостающее введение в контейнеризацию

08.02.2021 08:23:59 | Автор: admin

Эта статья помогла мне немного углубится в устройство и принцип работы контейнеров. Поэтому решил ее перевести. "Экосистема контейнеров иногда может сбивать с толку, этот пост может помочь вам понять некоторые запутанные концепции Docker и контейнеров. Мы также увидим, как развивалась экосистема контейнеров". Статья 2019 года.

Docker - одна из самых известных платформ контейнеризации в настоящее время, она была выпущена в 2013 году. Однако использование изоляции и контейнеризации началось раньше. Давайте вернемся в 1979 год, когда мы начали использовать Chroot Jail, и посмотрим на самые известные технологии контейнеризации, появившиеся после. Это поможет нам понять новые концепции.

Все началось с того, что Chroot Jail и системный вызов Chroot были введены во время разработки версии 7 Unix в 1979 году. Chroot jail предназначен для Change Root и считается одной из первых технологий контейнеризации. Он позволяет изолировать процесс и его дочерние элементы от остальной части операционной системы. Единственная проблема с этой изоляцией заключается в том, что корневой процесс может легко выйти из chroot. В нем никогда не задумывались механизмы безопасности. FreeBSD Jail была представлена в ОС FreeBSD в 2000 году и была предназначена для обеспечения большей безопасности простой изоляции файлов Chroot. В отличие от Chroot, реализация FreeBSD также изолирует процессы и их действия от Файловой системы.

Chroot Jail. Источник: https://linuxhill.wordpress.com/2014/08/09/014-setting-up-a-chroot-jail-in-crunchbang-11debian-wheezyChroot Jail. Источник: https://linuxhill.wordpress.com/2014/08/09/014-setting-up-a-chroot-jail-in-crunchbang-11debian-wheezy

Когда в ядро Linux были добавлены возможности виртуализации на уровне операционной системы, в 2001 году был представлен Linux VServer, который использовал chroot-подобный механизм в сочетании с security contexts (контекстами безопасности), так и виртуализацию на уровне операционной системы. Он более продвинутый, чем простой chroot, и позволяет запускать несколько дистрибутивов Linux на одном VPS.

В феврале 2004 года Sun (позже приобретенная Oracle) выпустила (Oracle) Solaris Containers, реализацию Linux-Vserver для процессоров X86 и SPARC. Контейнер Solaris - это комбинация элементов управления ресурсами системы и разделения ресурсов, обеспечиваемых zone.

Подобно контейнерам Solaris, первая версия OpenVZ была представлена в 2005 году. OpenVZ, как и Linux-VServer, использует виртуализацию на уровне ОС и был принят многими хостинговыми компаниями для изоляции и продажи VPS. Виртуализация на уровне ОС имеет некоторые ограничения, поскольку контейнеры и хост используют одну и ту же архитектуру и версию ядра, недостаток возникает в ситуациях, когда гостям требуются версии ядра, отличные от версии на хосте. Linux-VServer и OpenVZ требуют патча ядра, чтобы добавить некоторые механизмы управления, используемые для создания изолированного контейнера. Патчи OpenVZ не были интегрированы в ядро.

В 2007 году Google выпустил CGroups - механизм, который ограничивает и изолирует использование ресурсов (ЦП, память, дисковый ввод-вывод, сеть и т. д.) для набора процессов. CGroups были, в отличие от ядра OpenVZ, встроены в ядро Linux в 2007 году.

В 2008 году была выпущена первая версия LXC (Linux Containers). LXC похож на OpenVZ, Solaris Containers и Linux-VServer, однако он использует CGroups, которые уже реализованы в ядре Linux. Затем в 2013 году компания CloudFoundry создала Warden - API для управления изолированными, эфемерными средами с контролируемыми ресурсами. В своих первых версиях Warden использовал LXC.

В 2013 году была представлена первая версия Docker. Он выполняет виртуализацию на уровне операционной системы, как и контейнеры OpenVZ и Solaris.

В 2014 году Google представил LMCTFY, версию стека контейнеров Google с открытым исходным кодом, которая предоставляет контейнеры для приложений Linux. Инженеры Google сотрудничают с Docker над libcontainer и переносят основные концепции и абстракции в libcontainer. Проект активно не развивается, и в будущем ядро этого проекта, вероятно, будет заменено libcontainer.

LMCTFY запускает приложения в изолированных средах на том же ядре и без патчей, поскольку он использует CGroups, namespases и другие функции ядра Linux.

Фото Павла Червиньского для UnsplashФото Павла Червиньского для Unsplash

Google - лидер в контейнерной индустрии. Все в Google работает на контейнерах. Каждую неделю в инфраструктуре Google работает более 2 миллиардов контейнеров.

В декабре 2014 года CoreOS выпустила и начала поддерживать rkt (первоначально выпущенную как Rocket) в качестве альтернативы Docker.

Jails, VPS, Zones, контейнеры и виртуальные машины

Изоляция и управление ресурсами являются общими целями использования Jail, Zone, VPS, виртуальных машин и контейнеров, но каждая технология использует разные способы достижения этого, имеет свои ограничения и свои преимущества.

До сих пор мы вкратце видели, как работает Jail, и представили, как Linux-VServer позволяет запускать изолированные пользовательские пространства, в которых программы запускаются непосредственно в ядре операционной системы хоста, но имеют доступ к ограниченному подмножеству его ресурсов.

Linux-VServer позволяет запускать VPS, и для его использования необходимо пропатчить ядро хоста.

Контейнеры Solaris называются Zones.

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

Виртуальные машины могут быть System Virtual Machines (системными виртуальными машинами) или Process Virtual Machines (процессными виртуальными машинами). В повседневном использовании под словом виртуальные машины мы обычно имеем в виду системные виртуальные машины, которые представляют собой эмуляцию оборудования хоста для эмуляции всей операционной системы. Однако Process Virtual Machines, иногда называемый Application Virtual Machine (Виртуальной машиной приложения), используется для имитации среды программирования для выполнения отдельного процесса: примером является виртуальная машина Java.

Виртуализация на уровне ОС также называется контейнеризацией. Такие технологии, как Linux-VServer и OpenVZ, могут запускать несколько операционных систем, используя одну и ту же архитектуру и версию ядра.

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

Источник: https://fntlnz.wtf/post/why-containersИсточник: https://fntlnz.wtf/post/why-containers

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

VM vs Container. Источник: Docker BlogVM vs Container. Источник: Docker Blog

Контейнеры ОС vs контейнеры приложений

Виртуализация на уровне ОС помогает нам в создании контейнеров. Такие технологии, как LXC и Docker, используют этот тип изоляции.

Здесь у нас есть два типа контейнеров:

  • Контейнеры ОС, в которые упакована операционная система со всем стеком приложений (пример LEMP).

  • Контейнеры приложений, которые обычно запускают один процесс для каждого контейнера.

В случае с контейнерами приложений у нас будет 3 контейнера для создания стека LEMP:

  • сервер PHP (или PHP FPM).

  • Веб-сервер (Nginx).

  • Mysql.

Докер: контейнер или платформа?

Коротко: и то и другое

Подробный ответ:

Когда Docker начал использовать LXC в качестве среды выполнения контейнера, идея заключалась в том, чтобы создать API для управления средой выполнения контейнера, изолировать отдельные процессы, выполняющие приложения, и контролировать жизненный цикл контейнера и ресурсы, которые он использует. В начале 2013 года проект Docker должен был создать стандартный контейнер, как мы можем видеть в этом манифесте.

Манифест стандартного контейнера был удален.

Docker начал создавать монолитное приложение с множеством функций - от запуска облачных серверов до создания и запуска образов / контейнеров. Docker использовал libcontainer для взаимодействия с такими средствами ядра Linux, как Control Groups и Namespaces.

Давайте создадим контейнер с использованием СGroups и Namespaces

В этом примере я использую Ubuntu, но это должно работать для большинства дистрибутивов. Начните с установки CGroup Tools and утилиты stress, поскольку мы собираемся выполнить некоторые стресс-тесты.

sudo apt install cgroup-toolssudo apt install stress

Эта команда создаст новый контекст исполнения:

sudo unshare --fork --pid --mount-proc bashps aux

Команда "unshare" разъединяет части контекста исполнения процесса

Теперь, используя cgcreate, мы можем создать группы управления и определить два контроллера: один в памяти, а другой - в процессоре.

cgcreate -a $USER -g memory:mygroup -g cpu:mygroup ls /sys/fs/cgroup/{memory,cpu}/mygroup

Следующим шагом будет определение лимита памяти и его активация:

echo 3000000 > /sys/fs/cgroup/memory/mygroup/memory.kmem.limit_in_bytes cgexec -g memory:mygroup bash

Теперь давайте запустим stress для изолированного namespace, которое мы создали с ограничениями памяти.

stress --vm 1 --vm-bytes 1G --timeout 10s

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

Выполнение этих шагов поможет понять, как средства Linux, такие как CGroups и другие функции управления ресурсами, могут создавать изолированные среды в системах Linux и управлять ими.

Интерфейс libcontainer взаимодействует с этими средствами для управления контейнерами Docker и их запуска.

runC: Использование libcontainer без Docker

В 2015 году Docker анонсировал runC: легкую портативную среду выполнения контейнеров.

runC - это, по сути, небольшой инструмент командной строки для непосредственного использования libcontainer, без использования Docker Engine.

Цель runC - сделать стандартные контейнеры доступными повсюду.

Этот проект был передан в дар Open Container Initiative (OCI).

Репозиторий libcontainer сейчас заархивирован. На самом деле, libcontainer не забросили, а перенесли в репозиторий runC.

Перейдем к практической части и создадим контейнер с помощью runC. Начните с установки среды выполнения runC (прим. переводчика: если стоит docker то этого можно (нужно) не делать):

sudo apt install runc

Давайте создадим каталог (/mycontainer), в который мы собираемся экспортировать содержимое образа Busybox.

sudo sumkdir /mycontainercd /mycontainer/mkdir rootfs  docker export $(docker create busybox) | tar -C rootfs -xvf -

Используя команду runC, мы можем запустить контейнер busybox, который использует извлеченный образ и файл спецификации (config.json).

runc specrunc run mycontainerid

Команда runc spec изначально создает этот файл JSON:

{ "ociVersion": "1.0.1-dev", "process": {  "terminal": true,  "user": {   "uid": 0,   "gid": 0  },  "args": [   "sh"  ],  "env": [   "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",   "TERM=xterm"  ],  "cwd": "/",  "capabilities": {   "bounding": [    "CAP_AUDIT_WRITE",    "CAP_KILL",    "CAP_NET_BIND_SERVICE"   ],   "effective": [    "CAP_AUDIT_WRITE",    "CAP_KILL",    "CAP_NET_BIND_SERVICE"   ],   "inheritable": [    "CAP_AUDIT_WRITE",    "CAP_KILL",    "CAP_NET_BIND_SERVICE"   ],   "permitted": [    "CAP_AUDIT_WRITE",    "CAP_KILL",    "CAP_NET_BIND_SERVICE"   ],   "ambient": [    "CAP_AUDIT_WRITE",    "CAP_KILL",    "CAP_NET_BIND_SERVICE"   ]  },  "rlimits": [   {    "type": "RLIMIT_NOFILE",    "hard": 1024,    "soft": 1024   }  ],  "noNewPrivileges": true }, "root": {  "path": "rootfs",  "readonly": true }, "hostname": "runc", "mounts": [  {   "destination": "/proc",   "type": "proc",   "source": "proc"  },  {   "destination": "/dev",   "type": "tmpfs",   "source": "tmpfs",   "options": [    "nosuid",    "strictatime",    "mode=755",    "size=65536k"   ]  },  {   "destination": "/dev/pts",   "type": "devpts",   "source": "devpts",   "options": [    "nosuid",    "noexec",    "newinstance",    "ptmxmode=0666",    "mode=0620",    "gid=5"   ]  },  {   "destination": "/dev/shm",   "type": "tmpfs",   "source": "shm",   "options": [    "nosuid",    "noexec",    "nodev",    "mode=1777",    "size=65536k"   ]  },  {   "destination": "/dev/mqueue",   "type": "mqueue",   "source": "mqueue",   "options": [    "nosuid",    "noexec",    "nodev"   ]  },  {   "destination": "/sys",   "type": "sysfs",   "source": "sysfs",   "options": [    "nosuid",    "noexec",    "nodev",    "ro"   ]  },  {   "destination": "/sys/fs/cgroup",   "type": "cgroup",   "source": "cgroup",   "options": [    "nosuid",    "noexec",    "nodev",    "relatime",    "ro"   ]  } ], "linux": {  "resources": {   "devices": [    {     "allow": false,     "access": "rwm"    }   ]  },  "namespaces": [   {    "type": "pid"   },   {    "type": "network"   },   {    "type": "ipc"   },   {    "type": "uts"   },   {    "type": "mount"   }  ],  "maskedPaths": [   "/proc/kcore",   "/proc/latency_stats",   "/proc/timer_list",   "/proc/timer_stats",   "/proc/sched_debug",   "/sys/firmware",   "/proc/scsi"  ],  "readonlyPaths": [   "/proc/asound",   "/proc/bus",   "/proc/fs",   "/proc/irq",   "/proc/sys",   "/proc/sysrq-trigger"  ] }}

Альтернативой для создания кастомной спецификации конфигурации является использование oci-runtime-tool, подкоманда oci-runtime-tool generate имеет множество опций, которые можно использовать для выполнения разных настроек.

Для получения дополнительной информации см. Runtime-tools.

Используя сгенерированный файл спецификации JSON, вы можете настроить время работы контейнера. Мы можем, например, изменить аргумент для выполнения приложения.

Давайте посмотрим, чем отличается исходный файл config.json от нового:

Давайте теперь снова запустим контейнер и заметим, как он ожидает 10 секунд, прежде чем завершится.

Стандарты сред исполнения контейнеров

С тех пор, как контейнеры стали широко распространенными, различные участники этой экосистемы работали над стандартизацией. Стандартизация - ключ к автоматизации и обобщению передового опыта. Передав проект runC OCI, Docker начал использовать containerd в 2016 году в качестве среды выполнения контейнера, взаимодействующей с базовой средой исполнения низкого уровня runC.

docker info | grep -i runtime

Containerd полностью поддерживает запуск пакетов OCI и управление их жизненным циклом. Containerd (как и другие среды выполнения, такие как cri-o) использует runC для запуска контейнеров, но реализует также другие высокоуровневые функции, такие как управление образами и высокоуровневые API.

Интеграция containerd со средами выполнения Docker и OCIИнтеграция containerd со средами выполнения Docker и OCI

Сontainerd, Shim и RunC, как все работает вместе

runC построен на libcontainer, который является той же библиотекой, которая ранее использовалась для Docker Engine.

До версии 1.11 Docker Engine использовался для управления томами, сетями, контейнерами, образами и т. д.

Теперь архитектура Docker разбита на четыре компонента:

  • Docker engine

  • containerd

  • containerd-shim

  • runC

Бинарные файлы соответственно называются docker, docker-containerd, docker-containerd-shim и docker-runc.

Давайте перечислим этапы запуска контейнера с использованием новой архитектуры docker:

  1. Docker engine создает контейнер (из образа) и передает его в containerd.

  2. Containerd вызывает containerd-shim

  3. Containerd-shim использует runC для запуска контейнера

  4. Containerd-shim позволяет среде выполнения (в данном случае runC) завершиться после запуска контейнера

Используя эту новую архитектуру, мы можем запускать контейнеры без служб (daemon-less containers), и у нас есть два преимущества:

  1. runC может завершиться после запуска контейнера, и нам не нужны запущенными все процессы исполнения.

  2. containerd-shim сохраняет открытыми файловые дескрипторы, такие как stdin, stdout и stderr, даже когда Docker и /или containerd завершаются.

Если runC и Containerd являются средами исполнения, какого черта мы используем оба для запуска одного контейнера?

Это, наверное, один из самых частых вопросов. Поняв, почему Docker разбил свою архитектуру на runC и Containerd, вы понимаете, что оба являются средами исполнения.

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

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

Среда исполнения низкого уровня (например, runC) должна быть легкой, быстрой и не конфликтовать с другими более высокими уровнями управления контейнерами. Когда вы создаете контейнер Docker, он фактически управляет двумя средами исполнения containerd и runC.

Вы можете найти множество сред исполнения контейнеров, некоторые из них стандартизированы OCI, а другие нет, некоторые являются средами исполнения низкого уровня, а другие представляют собой нечто большее и реализуют уровень инструментов для управления жизненным циклом контейнеров и многое другое:

  • передача и хранение образов,

  • завершение и наблюдение за контейнерами,

  • низкоуровневое хранилище,

  • сетевые настройки,

  • и т.п.

Мы можем добавить новую среду исполнения с помощью Docker, выполнив:

sudo dockerd --add-runtime=<runtime-name>=<runtime-path> 

Например:

sudo apt-get install nvidia-container-runtimesudo dockerd --add-runtime=nvidia=/usr/bin/nvidia-container-runtime

Интерфейс среды исполнения контейнера (Container Runtime Interface)

Kubernetes - одна из самых популярных систем оркестровки. С ростом числа сред выполнения контейнеров Kubernetes стремится быть более расширяемым и взаимодействовать с большим количеством сред выполнения контейнеров, помимо Docker.

Первоначально Kubernetes использовал среду исполнения Docker для запуска контейнеров, и она по-прежнему остается средой исполнения по умолчанию.

Однако CoreOS хотела использовать Kubernetes со средой исполнения RKT и предлагала патчи для Kubernetes, чтобы использовать эту среду исполнения в качестве альтернативы Docker.

Вместо изменения кодовой базы kubernetes в случае добавлении новой среды исполнения контейнера создатели Kubernetes решили создать CRI (Container Runtime Interface), который представляет собой набор API-интерфейсов и библиотек, позволяющих запускать различные среды исполнения контейнеров в Kubernetes. Любое взаимодействие между ядром Kubernetes и поддерживаемой средой выполнения осуществляется через CRI API.

Вот некоторые из плагинов CRI:

CRI-O:

CRI-O - это первая среда исполнения контейнера, созданная для интерфейса CRI kubernetes. Cri-O не предназначен для замены Docker, но его можно использовать вместо среды исполнения Docker в Kubernetes.

Containerd CRI :

С cri-containerd пользователи могут запускать кластеры Kubernetes, используя containerd в качестве базовой среды исполнения без установленного Docker.

gVisor CRI:

gVisor - это проект, разработанный Google, который реализует около 200 системных вызовов Linux в пользовательском пространстве для дополнительной безопасности по сравнению с контейнерами Docker, которые работают непосредственно поверх ядра Linux и изолированы с помощью namespace.

Google Cloud App Engine использует gVisor CRI для изоляции клиентов.

Среда исполнения gVisor интегрируется с Docker и Kubernetes, что упрощает запуск изолированных контейнеров.

CRI-O Kata Containers

Kata Containers - это проект с открытым исходным кодом, создающий легкие виртуальные машины, которые подключаются к экосистеме контейнеров. CRI-O Kata Containers позволяет запускать контейнеры Kata в Kubernetes вместо среды выполнения Docker по умолчанию.

Проект Moby

От проекта создания Docker как единой монолитной платформы отказались и родился проект Moby, в котором Docker состоит из множества компонентов, таких как RunC.

Источник: Solomon Hykes TwitterИсточник: Solomon Hykes Twitter

Moby - это проект по организации и разделения на модули Docker. Это экосистема разработки. Обычные пользователи Docker не заметят никаких изменений.

Источник: Solomon Hykes TwitterИсточник: Solomon Hykes Twitter

Moby помогает в разработке и запуске Docker CE и EE (Moby - это исходный код Docker), а также в создании среды разработки для других сред исполнения и платформ.

Open Containers Initiative

Как мы видели, Docker пожертвовал RunC Open Container Initiative (OCI), но что это?

OCI - это открытая структура, запущенная в 2015 году Docker, CoreOS и другими лидерами контейнерной индустрии.

Open Container Initiative (OCI) направлена на установление общих стандартов для контейнеров, чтобы избежать потенциальной фрагментации и разделения внутри экосистемы контейнеров.

Он содержит две спецификации:

  • runtime-spec: спецификация исполнения

  • image-spec: спецификация образов

Контейнер, использующий другую среду исполнения, можно использовать с Docker API. Контейнер, созданный с помощью Docker, должен работать с любым другим движком.

На этом статья заканчивается.

Буду рад замечаниям и возможно неточностям в статье оригинального автора. Это позволит избежать заблуждений в понимании внутреннего устройства контейнеров. Если нет возможности комментирования на хабре можете обсудить тут в комментариях.

Подробнее..

Перевод Как заменить container runtime в Kubernetes

14.03.2021 18:20:23 | Автор: admin

Братцы! Скорее всего вы уже знаете, что Kubernetes отказался от поддержки Docker в качестве среды выполнения контейнеров (container runtime) в будующих версиях. В релизе 1.20, вышедшем в конце 2020 года Dockershim помечен как не рекомендованный (depricated). В релизе 1.22, выход которого запланирован на конец 2021 года, от его поддержки планируют полностью отказаться.

Если вы используете управляемые кластеры Kubernetes (такие как GKE, EKS, AKS) это не станет для вас серьезной проблемой и скорее всего переключение будет простым. Но если вы управляете кластером самостоятельно (например с помощью kubeadm) и используете Docker в container runtime, рано или поздно, вам придется заменить ее, чтобы иметь возможность обновлениять Kubernetes до последних версий.

Задача этой статьи не дать исчерпывающую информацию о причинах такого решения со стороны разработчиков Kubernetes или подробно изучить поведения конкретных container runtime в кластере Kubernetes. Вместо этого мы шаг за шагом разберемся как переключить Docker container runtime на другое решение, поддерживающее стандарт Container Runtime Interface(CRI). Если вас интересуют причины из-за которых Docker больше не рекомендован к использованию, ознакомьтесь со статьей из официального блога Kubernetes Don't Panic: Kubernetes and Docker.

Чтобы не пропустить новые статьи подписывайтесь на телеграм-канал Mops DevOps

Что проверять в первую очередь

Влияние на рабочие нагрузки, выполняемые в вашем кластере, должно быть минимальным. Единственное, о чем вам нужно позаботиться, - это используете ли вы Docker-in-Docker в любой из ваших контейнерных рабочих нагрузок, смонтировав сокет Docker /var/run/docker.sock. В этом случае вам нужно будет найти альтернативу (например, Kaniko), прежде чем переключаться с Docker на новую container runtime.

Также настоятельно рекомендуется сделать резервную копию ваших данных, прежде чем переходить к переключению среды выполнения контейнера!

Приступим к работе!

Отлично, теперь, когда вы готовы к переключению container runtime, можно начинать. В этой статье бедем использовать containerd в качестве container runtime, но приведенные ниже шаги можно адаптировать к другой среде выполнения контейнера, например, CRI-O.

Мы начнем с рабочих узлов (worker nodes) и только потом выполним аналогичные действия на мастерах (control plane).

Worker nodes

Указанные ниже шаги нужно выполнить на всех рабочих узлах кластера.

1) Вначале выполним drain и cordon узла кластера, чтобы эвакуировать нагрузки с него и предотвратить планирование новых нагрузок во время выполнения последующих операций:

kubectl cordon <node_name>kubectl drain <node_name>

Замечание: если на узлах кластера запущены DaemonSets, необходимо использовать флаг --ignore-daemonsets, чтобы продолжить эвакуацию остальных pods. Не волнуйтесь kubelet эти pods автоматически пересоздаст с помощью новой container runtime, когда процедура переключения будет завершена. Если у вас есть критические сервисы, запущенные в DaemonSet, и вы не хотите, чтобы они работали во время процесса переключения, вы можете либо указать nodeSelector в своем DaemonSet, либо полностью удалить и переустановить их в конце процесса.

2) Останавливаем сервис kubelet:

sudo systemctl stop kubeletsudo systemctl status kubelet

3) Удаляем Docker

Я не буду подробно описывать команды, поскольку это зависит от вашего дистрибутива Linux и способа установки Docker. Просто будьте осторожны, если вы хотите полностью очистить артефакты Docker, возможно, вам придется вручную удалить некоторые файлы (например, /var/ lib/docker).

Подробную инструкцию вы найдете в документации Docker.

4) Устанавливаем countainerd используя официальному руководству для вашей версии операционной системы.

5) Выполняем Enableи Startсервиса containerd:

sudo systemctl enable containerdsudo systemctl start containerdsudo systemctl status containerd

6) Kubernetes взаимодействует с container runtime через плагин CRI . Убедитесь, что этот плагин не был отключен при установке containerd.

Проверим файл конфигурации:

vim /etc/containerd/config.toml проверяем параметрdisabled_plugins = [""]

Если на предыдущем шаге внесены изменения в конфигурационный файл, необходимо перезагрузить сервис containerd:

sudo systemctl restart containerd

7) Отредактируем конфигурационный файл kubelet:

vim /var/lib/kubelet/kubeadm-flags.envДобавим в конфигурационный файл флаги для переменной KUBELET_KUBEADM_ARGS(при необходимости измените путь к container runtime)--container-runtime=remote --container-runtime-endpoint=/run/containerd/containerd.sock

8) Запускаем сервис kubelet:

sudo systemctl start kubelet

9) Проверяем, что на узле запущена требуемая версия container runtime:

kubectl describe node <node_name>
System Info:  Machine ID:                 21a5dd31f86c4  System UUID:                4227EF55-BA3BCCB57BCE  Boot ID:                    77229747-9ea581ec6773  Kernel Version:             3.10.0-1127.10.1.el7.x86_64  OS Image:                   Red Hat Enterprise Linux Server 7.8 (Maipo)  Operating System:           linux  Architecture:               amd64>>Container Runtime Version:  containerd://1.4.3  Kubelet Version:            v1.20.2  Kube-Proxy Version:         v1.20.2

10) Выполняем Uncordon на узле, чтобы разрешить планировать на него нагрузки, и проверим статус работы pods:

kubectl uncordon <node_name>

Вот и все, как только все ваши поды будут перезапущены, вы можете перейти к настройке следующего узла кластера!

Control Plane

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

Пока новая container runtime будет загружать образы kube-apiserver, etcd и coredns и создавать соответствующие pods, кластер будет недоступен. У вас также не должна быть возможности запускать команду kubectl.

Вот несколько советов, которые помогут вам следить за запуском container runtime и устранять потенциальные проблемы:

1) Используем journalctl, чтобы отслеживать изменения в журналах kubelet:

journalctl -u kubelet

2) Проверяем журналы containerd:

journalctl -u containerd

3) Используем утилиту crictl, чтобы убедится, что контейнеры запущены:

crictl --runtime-endpoint /run/containerd/containerd.sock ps

4) После замены container runtime убедимся, что используем требуемую версию, выполнив команду на всех узлах кластера:

kubectl describe node <master_node_name>также можем выполнить команду, она выведет информацию сразу по всем узлам кластераkubectl get node -o wide

Поздравляю! Кластер Kubernetes настроен без Docker, теперь проблем с обновлением на новые версии возникнуть не должно.


Телеграм-канал Mops DevOps - анонсы вебинаров и конференций, полезные статьи и видео, а так же регулярные скидки на обучение!

Подробнее..

Перевод Миграция с Docker на containerd в среде Kubernetes

05.04.2021 10:08:01 | Автор: admin


Kubernetes отказывается от Docker для выполнения контейнеров после версии 1.20. (Прим. переводчика: в декабре мы уже писали о том, как это изменение повлияет на задачи разработчиков и инженеров эксплуатации: Docker is deprecated и как теперь быть?)


Без паники. Контейнеры Docker все еще поддерживаются, но без dockershim/Docker слоя между Kubernetes и containerd, который будет удален, начиная с версии 1.22+.


Если вы используете Docker, нужно перейти на поддерживаемый интерфейс container runtime interface (CRI). Хорошим вариантом будет containerd он уже есть у вас на ноде Kubernetes, если вы работаете с Docker.


Дополнительное преимущество меньше издержек благодаря отсутствию dockershim и уровней преобразования Docker, как видно на иллюстрации.



Переход с dockershim на containerd CRI


Как мигрировать?


Сначала проверяем, какая среда запуска контейнеров (container runtime) у нас используется. Это можно сделать командой kubectl get nodes -o wide


Как видите, здесь у нас Docker.


NAME       STATUS   ROLES                  AGE     VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION                             CONTAINER-RUNTIMEk8s-cn01   Ready    control-plane,master   78m     v1.20.4   10.65.79.164   <none>        Ubuntu 20.04.2 LTS   5.4.0-67-generic                           docker://20.10.5k8s-wn01   Ready    <none>                 64m     v1.20.4   10.65.79.131   <none>        Ubuntu 20.04.2 LTS   5.4.0-67-generic                           docker://20.10.5k8s-wn02   Ready    <none>                 4m16s   v1.20.4   10.65.79.244   <none>        CentOS Linux 8       4.18.0-240.15.1.el8_3.centos.plus.x86_64   docker://20.10.5

kubectl get nodes -o wide


Проверим, есть ли у нас containerd CLI /usr/bin/ctr и неймспейс moby из Docker.


NAME LABELSmoby

просмотр неймспейсов


Можно посмотреть запущенные контейнеры в этом неймспейсе.


CONTAINER                                                           IMAGE    RUNTIME04f9500885c473c9cb2b4f8d09dc4feea5c24838519b9a01251011830bab16a2    -        io.containerd.runc.v257d4c75ab9947829228a087b857b203c48a9d1c83de0a1b49af3624fb08c9d33    -        io.containerd.runc.v2934c007a259018a5cbda56dd8e066a66f2c9cfcb8003e7f8d25833fe462582fd    -        io.containerd.runc.v294315822d8f8a05e1be5adb7e5c18add33cbf2604057100c87572b5fc55169cd    -        io.containerd.runc.v2dfa01906e845239c74a0b35d457e845382468dd9ad6e99dd0c16be30f8a23a2d    -        io.containerd.runc.v2

Просмотр списка контейнеров в неймспейсе moby


Если все выглядит нормально, можно изменить CRI. Меняем по одной ноде за раз, начиная с рабочих и заканчивая мастером. Если мастер только один, вы временно потеряете доступ к кластеру, но он восстановится сам.


Cordon и drain


Выполняем cordon и drain для нод, чтобы перенести поды на другие ноды.


root@k8s-cn01:~# kubectl cordon k8s-wn01node/k8s-wn01 cordonedroot@k8s-cn01:~# kubectl drain k8s-wn01 --ignore-daemonsetsnode/k8s-wn01 already cordonedWARNING: ignoring DaemonSet-managed Pods: kube-system/kube-proxy-9wnh4, kube-system/weave-net-pgptmevicting pod default/nginx-6799fc88d8-r44x9pod/nginx-6799fc88d8-r44x9 evictednode/k8s-wn01 evictedroot@k8s-cn01:~# kubectl get nodesNAME       STATUS                     ROLES                  AGE    VERSIONk8s-cn01   Ready                      control-plane,master   138m   v1.20.4k8s-wn01   Ready,SchedulingDisabled   <none>                 124m   v1.20.4k8s-wn02   Ready                      <none>                 64m    v1.20.4

Останавливаем сервисы


 systemctl stop kubelet  systemctl stop docker

остановка kubelet и docker


Удаляем Docker (по желанию)


Удалять Docker не обязательно, но так все будет понятнее, на диске освободится немного места, а риска ошибок будет меньше.


apt purge docker-ce docker-ce-cliORyum remove docker-ce docker-ce-cli

удаление docker


Конфигурация containerd


Отключим строку disabled_plugins в /etc/containerd/config.toml, чтобы CRI загрузился.


#disabled_plugins = ["cri"]

/etc/containerd/config.tom


Если для cotainerd нет файла конфигурации, создайте новый дефолтный файл.


containerd config default > /etc/containerd/config.toml

создание файла конфигурации


Перезапустим containerd.


systemctl restart containerd

Меняем среду запуска


Правим файл /var/lib/kubelet/kubeadm-flags.env и добавляем среду containerd во флаги --container-runtimeremote и --container-runtimeendpoint=unix:///run/containerd/containerd.sock"


Файл kubeadm-flags будет выглядеть как-то так:


KUBELET_KUBEADM_ARGS="--cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2--resolv-conf=/run/systemd/resolve/resolv.conf --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock"

/var/lib/kubelet/kubeadm-flags.env


Запускаем kubelet


Изменив среду запуска, запускаем сервис kubelet.


systemctl start kubelet

запуск kubelet


Проверяем


Запускаем kubectl get nodes -o wide и видим, что у измененной ноды новая среда запуска.


NAME       STATUS                   ROLES                  AGE    VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION                             CONTAINER-RUNTIMEk8s-cn01   Ready                    control-plane,master   131m   v1.20.4   10.65.79.164   <none>        Ubuntu 20.04.2 LTS   5.4.0-67-generic                           docker://20.10.5k8s-wn01   Ready,,SchedulingDisabled        <none>                 117m   v1.20.4   10.65.79.131         <none>        Ubuntu 20.04.2 LTS   5.4.0-67-generic                           containerd://1.4.4k8s-wn02   Ready             <none>                 57m    v1.20.4   10.65.79.244   <none>        CentOS Linux 8       4.18.0-240.15.1.el8_3.centos.plus.x86_64   docker://20.10.5

Измененная нода все еще имеет статус cordoned. Отменим его.


root@k8s-cn01:~# kubectl uncordon k8s-wn01node/k8s-wn01 uncordonedroot@k8s-cn01:~# kubectl get nodesNAME       STATUS   ROLES                  AGE    VERSIONk8s-cn01   Ready    control-plane,master   143m   v1.20.4k8s-wn01   Ready    <none>                 129m   v1.20.4k8s-wn02   Ready    <none>                 69m    v1.20.4

Если проверить неймспейсы на ноде сейчас, увидим k8s.io. Неймспейс moby теперь пуст, никакие контейнеры в нем не выполняются все мигрировало в k8s.io.


root@k8s-wn01:~# ctr namespaces listNAME   LABELSk8s.iomobyroot@k8s-wn01:~# ctr --namespace moby container listCONTAINER    IMAGE    RUNTIMEroot@k8s-wn01:~# ctr --namespace k8s.io container listCONTAINER                                                           IMAGE                                    RUNTIME08d4b5ca1f0ddd08fff7f64ea4eb12be66b8ec860d119565e553c84d16942d26    docker.io/weaveworks/weave-kube:2.8.1    io.containerd.runc.v21c9e3f61f542b12abb4b849075b084fb7fe3f69b89ce668d73022c2cd647bcd1    k8s.gcr.io/pause:3.2                     io.containerd.runc.v21f8e0c5a6f8219de1c8f25bbb28d5d5c71b74e9ccfb9620007701847d29f23a2    k8s.gcr.io/kube-proxy:v1.20.4            io.containerd.runc.v239296ebd6017a7c83cd58004c94708c927f10a996a4e6ba0bbf003c6713fe713    docker.io/weaveworks/weave-kube:2.8.1    io.containerd.runc.v267f812954f46fa5c1f6ab39e681e2481f868309f28bd1b8ba44cce53f5c0071c    docker.io/weaveworks/weave-npc:2.8.1     io.containerd.runc.v29caed1d57d40cedef736e45adf550eda6a0befd32712e5b6af5d711681ba71f0    k8s.gcr.io/pause:3.2                     io.containerd.runc.v2

просмотр нового неймспейса k8s.io


Мы успешно изменили CRI, теперь можно повторить все то же самое для следующей ноды.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru