Docker machine что это
Docker под Windows для разработки, разбор подводных камней
Данная публикация является разбором особенностей контейнерной виртуализации Docker под системой Windows.
Она не претендует на роль исчерпывающей и по мере необходимости будет обновляться и дополняться.
За практическим руководством с нуля советую обратиться к этой публикации.
Содержание
Предварительные настройки
Контейнерная виртуализация или виртуализация на уровне операционной системы Docker нативно работает только на дистрибутивах Linux и FreeBSD (экспериментально).
На Windows вам понадобится гостевая Linux система либо специальная минималистичная виртуальная машина с ядром Linux от разработчиков Docker, которая и ставится из коробки.
Само собой разумеется, что вы включили виртуализацию у себя в BIOS/UEFI
Пункт настройки может называться по-разному: VT-x, VT-d, Intel VT, AMD-V, Virtualization Technology.
Еще одним минимальным системным требованием будет разрядность системы x64 и версия не ниже Windows 7 Pro.
Выбор между Docker Toolbox on Windows или Docker for Windows
Сборка включается в себя сам docker, утилиту docker-compose, утилиту для работы с виртуальной машиной docker-machine и клиент Kitematic.
Используется виртуальная машина (по умолчанию на VirtualBox) с минималистичным Linux окружением.
Позже для новых операционных систем выпустили Docker for Windows и Docker for Mac, которая на текущий момент является актуальной версией и продолжает развиваться.
Выбор между версиями не сложный:
— Если у вас Windows 10 x64 Pro, Enterprise или Education то включаем службу Hyper-V и ставим Docker for Windows.
Заметьте, что после включения службы Hyper-V пропадет возможность запускать и создавать x64 виртуальные машины на VirtualBox.
— Если же у вас другая версия Windows(7 Pro, 8, 8.1, 10 Home) то ставим VirtualBox и Docker Toolbox on Windows.
Несмотря на то, что Docker Toolbox разработчиками признан устаревшим работа с ним слабо отличается от Docker for Windows.
Вместе с установкой Docker Toolbox будет создана виртуальная машина.
В самом VirtualBox можно будет добавить оперативной памяти и ядер процессора на ваше усмотрение.
Windows контейнеры и Linux контейнеры
Docker for Windows предоставляет возможность переключать контейнеризацию между Linux и Windows версией.
В режиме Windows контейнеризации вы можете запускать только Windows приложения.
Замечу, что на май 2018 года в официальном Docker Hub существует всего 13 образов для Windows.
После включения Windows контейнеризации не забудьте добавить внешнюю сеть.
В конфигурационном файле docker-compose.yml это выглядит так:
Особенности монтирования папок
На примонтированных volume-ах не кидаются события файловой системы, поэтому inotify-tools не работает.
Спасибо пользователю eee
Если вы разрабатываете свой проект и пользуетесь docker-compose вне домашней папки то вам нужно будет проделать некоторые манипуляции.
Используя Docker for Windows для монтирования нового диска у вашего локального пользователя обязательно должен стоять пароль, который будет использоваться для доступа к shared папки.
Особенность заключается в том, что монтируемые внутрь контейнера диск будет монтироваться как от удаленной машины //10.0.75.1/DISK_DRIVE по протоколу SMB.
Для Docker Toolbox диски монтируются в самом VirtualBox на вкладке «Общие папки»
Пример для диска «D»:
Права доступа к монтируемым файлам и папкам
Как бы вам не хотелось, но для всех примонтированных из хост-машины файлов и папок будут стоять права 755 (rwx r-x r-x) и поменять их вы не сможете.
Остро встает вопрос при монтировании внутрь файла закрытого SSH ключа, права на который должны быть только у владельца(например 600).
В данном случае либо генерируют ключ при создании образа, либо прокидывают сокет ssh-agent с хост-машины.
Монтирование с хост-машины или volume
Монтирование внутрь контейнера происходит с использованием сети и протокола SMB, следовательно, внутри контейнера диск «D:\» будет примонтирован из источника //10.0.75.1/D
Использование volume внутри контейнера отображается как монтирование локального диска /dev/sda1, что влияет на скорость работы.
Простым тестом копирование файла на обычном HDD скорость работы получилась следующая:
Такая разница в скорости скорее всего связана с тем, что в volume данные сбрасываются на диск постепенно, задействуя кеш в ОЗУ.
Особенности разметки диска GPT и MBR
Данный пункт не является истинной так как опровергающей или подтверждающей информации в интернете найти не смог.
Если на хост-машине таблица разделов MBR, то контейнер с MySQL/MariaDB может упасть с ошибкой:
По умолчанию в базе данных включеён параметр innodb_use_native_aio, отвечающий за асинхронный ввод/вывод и его надо будет выключить.
Данная проблема также встречается на некоторых версиях MacOS.
Docker Toobox to Windows
Главное правило: начинать работу с запуска ярлыка на рабочем столе «Docker Quickstart Terminal», это решает 80% проблем.
— Бывает возникают проблемы с отсутствия переменных окружения, решается командой:
— Если все же возникают проблемы из разряда «docker: error during connect», необходимо выполнить:
Название Docker Machine по умолчанию default.
Docker Swarm
Ни в Docker for Mac, ни в Docker for Windows — нет возможности использовать запущенные демоны в качестве клиентов кластера (swarm members).
Спасибо пользователю stychos
Проблемы с кодировкой
Используя Docker Toolbox(на Docker for Windows не удалось воспроизвести) нашлась проблема с тем, что русские комментарии в docker-compose.yml файле приводили к ошибке:
Полезные ссылки
Заключение
Особенности работы с Docker контейнеризацией на системе Windows не отличается от работы на Linux за исключение разобранных выше.
В статье я умышленно не упомянул заметно низкую скорость работы контейнеров и overhead используя систему Windows как само собой разумеющееся.
Буду рад услышать ваши отзывы. Не стесняйтесь предлагать улучшения или указывать на мои ошибки.
Что такое Docker: краткий экскурс в историю и основные абстракции
10 августа в Слёрм стартовал видеокурс по Docker, в котором мы разбираем его полностью — от основных абстракций до параметров сети.
В этой статье поговорим об истории появления Docker и его основных абстракциях: Image, Cli, Dockerfile. Лекция рассчитана на новичков, поэтому вряд ли будет интересна опытным пользователям. Здесь не будет крови, аппендикса и глубокого погружения. Самые основы.
Что такое Docker
Посмотрим на определение Docker из Википедии.
Docker — это программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации.
Из этого определения ничего непонятно. Особенно непонятно, что значит «в средах с поддержкой контейнеризации». Чтобы разобраться, вернёмся в прошлое. Начнём с эпохи, которую я условно называю «Монолитной эрой».
Монолитная эра
Монолитная эра — это начало 2000-х, когда все приложения были монолитными, с кучей зависимостей. Разработка шла долго. При этом серверов было не так много, мы все их знали по именам и мониторили. Есть такое забавное сравнение:
Pets — это домашние животные. В монолитной эре мы относились к своим серверам, как к домашним животным, холили и лелеяли, пылинки сдували. А для лучшего управления ресурсами использовали виртуализацию: брали сервер и пилили на несколько виртуальных машин, тем самым обеспечивая изоляцию окружения.
Системы виртуализации на базе гипервизора
Про системы виртуализации наверняка все слышали: VMware, VirtualBox, Hyper-V, Qemu KVM и т. д. Они обеспечивают изоляцию приложений и управление ресурсами, но у них есть и минусы. Чтобы сделать виртуализацию, нужен гипервизор. А гипервизор — это оверхед ресурсов. Да и сама виртуальная машина обычно целая махина — тяжелый образ, на нём операционная система, Nginx, Apache, возможно и MySQL. Образ большой, виртуальной машиной неудобно оперировать. Как следствие, работа с виртуалками может быть медленной. Чтобы решить эту проблему, создали системы виртуализации на уровне ядра.
Системы виртуализации на уровне ядра
Виртуализацию на уровне ядра поддерживают системы OpenVZ, Systemd-nspawn, LXC. Яркий пример такой виртуализации — LXC (Linux Containers).
LXC — система виртуализации на уровне операционной системы для запуска нескольких изолированных экземпляров операционной системы Linux на одном узле. LXC не использует виртуальные машины, а создаёт виртуальное окружение с собственным пространством процессов и сетевым стеком.
По сути LXC создаёт контейнеры. В чём разница между виртуальными машинами и контейнерами?
Контейнер не подходит для изолирования процессов: в системах виртуализации на уровне ядра находят уязвимости, которые позволяют вылезти из контейнера на хост. Поэтому если вам нужно что-то изолировать, то лучше использовать виртуалку.
Различия между виртуализацией и контейнеризацией можно увидеть на схеме.
Бывают аппаратные гипервизоры, гипервизоры поверх ОС и контейнеры.
«Железные» гипервизоры — это крутая штука, если вы действительно хотите что-то изолировать. Потому что там есть возможность изолировать на уровне страниц памяти, процессоров.
Есть гипервизоры как программа, и есть контейнеры, о них мы и будем говорить дальше. В системах контейнеризации гипервизора нет, но есть Container Engine, который создаёт контейнеры и управляет ими. Штука это более легковесная, поэтому за счет работы с ядром оверхед меньше, или его нет совсем.
Что используется для контейнеризации на уровне ядра
Основные технологии, которые позволяют создавать изолированный от других процессов контейнер, — это Namespaces и Control Groups.
Namespaces: PID, Networking, Mount и User. Есть ещё, но для простоты понимания остановимся на этих.
PID Namespace ограничивает процессы. Когда мы, например, создаём PID Namespace, помещаем туда процесс, то он становится с PID 1. Обычно в системах PID 1 — это systemd или init. Соответственно, когда мы помещаем процесс в новый namespace, он тоже получает PID 1.
Networking Namespace позволяет ограничить/изолировать сеть и внутри уже размещать свои интерфейсы. Mount — это ограничение по файловой системе. User — ограничение по юзерам.
Control Groups: Memory, CPU, IOPS, Network — всего около 12 настроек. Иначе их ещё называют Cgroups («Cи-группы»).
Control Groups управляют ресурсами для контейнера. Через Control Groups мы можем сказать, что контейнер не должен потреблять больше какого-то количества ресурсов.
Чтобы контейнеризация полноценно работала, используются дополнительные технологии: Capabilities, Copy-on-write и другие.
Capabilities — это когда мы говорим процессу, что он может делать, а чего не может. На уровне ядра это просто битовые карты со множеством параметров. Например, пользователь root имеет полные привилегии, может делать всё. Сервер времени может изменять системное время: у него есть capabilities на Time Capsule, и всё. С помощью привилегий можно гибко настроить ограничения для процессов, и тем самым обезопасить себя.
Система Copy-on-write позволяет нам работать с образами Docker, использовать их более эффективно.
На данный момент Docker имеет проблемы с совместимостью Cgroups v2, поэтому в статье рассматриваются именно Cgroups v1.
Но вернёмся к истории.
Когда появились системы виртуализации на уровне ядра, их начали активно применять. Оверхед на гипервизор пропал, но некоторые проблемы остались:
Чтобы все эти проблемы решить, пришла следующая эра.
Эра контейнеров
Когда наступила Эра контейнеров, сменилась философия работы с ними:
Помните, я говорил про pets vs cattle? Раньше инстансы были подобны домашним животным, а теперь стали как cattle — скот. Раньше был монолит — одно приложение. Теперь это 100 микросервисов, 100 контейнеров. У каких-то контейнеров может быть по 2-3 реплики. Нам становится не столь важно контролировать каждый контейнер. Нам скорее важна доступность самого сервиса: того, что делает этот набор контейнеров. Это меняет подходы в мониторинге.
В 2014-2015 годах случился расцвет Docker — той технологии, о которой мы и будем сейчас говорить.
Docker изменил философию и стандартизировал упаковку приложения. С помощью Docker мы можем упаковать приложение, отправить его в репозиторий, скачать оттуда, развернуть.
В Docker-контейнер мы закладываем всё необходимое, поэтому решается проблема зависимостей. Docker гарантирует воспроизводимость. Я думаю, многие сталкивались с невоспроизводимостью: у тебя всё работает, пушишь на продакшен, там это перестает работать. С Docker эта проблема уходит. Если твой Docker-контейнер запускается и делает то, что требуется делать, то с большой долей вероятности он запустится на продакшене и там сделает то же самое.
Отступление про оверхед
По поводу оверхед постоянно идут споры. Кто-то считает, что Docker не несёт дополнительную нагрузку, так как использует ядро Linux и все его процессы, необходимые для контейнеризации. Мол, «если вы говорите, что Docker — это оверхед, то тогда и ядро Linux оверхед».
С другой стороны, если углубиться, то в Docker и правда есть несколько вещей, про которые с натяжкой можно сказать, что это оверхед.
Первое — это PID namespace. Когда мы в namespace помещаем какой-то процесс, ему присваивается PID 1. В то же время у этого процесса есть ещё один PID, который находится на хостовом namespace, за пределами контейнера. Например, мы запустили в контейнере Nginx, он стал PID 1 (мастер-процесс). А на хосте у него PID 12623. И сложно сказать, насколько это оверхед.
Вторая штука — это Cgroups. Возьмём Cgroups по памяти, то есть возможность ограничивать контейнеру память. При её включении активируются счётчики, memory accounting: ядру надо понимать, сколько страниц выделено, а сколько ещё свободно для этого контейнера. Это возможно оверхед, но точных исследований о том, как он влияет на производительность, я не встречал. И сам не замечал, что приложение, запущенное в Docker, вдруг резко теряло в производительности.
И ещё одно замечание о производительности. Некоторые параметры ядра прокидываются с хоста в контейнер. В частности, некоторые сетевые параметры. Поэтому если вы хотите запустить в Docker что-то высокопроизводительное, например то, что будет активно использовать сеть, то вам, как минимум, надо эти параметры подправить. Какой-нибудь nf_conntrack, к примеру.
О концепции Docker
Docker состоит из нескольких компонентов:
Схематично это выглядит примерно вот так:
На Docker_host работает Docker daemon, запускает контейнеры. Есть Client, который передаёт команды: собери образ, скачай образ, запусти контейнер. Docker daemon ходит в registry и выполняет их. Docker-клиент может обращаться и локально (к юникс-сокету), и по TCP с удалённого хоста.
Пройдёмся по каждому компоненту.
Docker daemon (демон) — это серверная часть, она работает на хост-машине: скачивает образы и запускает из них контейнеры, создаёт сеть между контейнерами, собирает логи. Когда мы говорим «создай образ», этим тоже занимается демон.
Docker CLI — клиентская часть Docker, консольная утилита для работы с демоном. Повторю, она может работать не только локально, но и по сети.
Базовые команды:
docker ps — показать контейнеры, которые сейчас запущены на Docker-хосте.
docker images — показать образы, скачанные локально.
docker search <> — поиск образа в registry.
docker pull <> — скачать образ из registry на машину.
docker build — собрать образ.
docker run <> — запуск контейнер.
docker rm <> — удалить контейнер.
docker logs <> — логи контейнера
docker start/stop/restart <> — работа с контейнером
Если вы освоите эти команды и будете уверенно ими пользоваться, то считайте, что на 70% освоили Docker на уровне пользователя.
Dockerfile — инструкция для создания образа. Почти каждая команда инструкции — новый слой. Посмотрим на примере.
Примерно так выглядит Dockerfile: слева команды, справа — аргументы. Каждая команда, что здесь есть (и вообще пишется в Dockerfile), создаёт новый слой в Image.
Даже глядя на левую часть, можно примерно понять, что происходит. Мы говорим: «создай нам папку» — это один слой. «Сделай папку рабочей» — это ещё один слой, и так далее. Слоёный пирог упрощает жизнь. Если я создам ещё один Dockerfile и в последней строчке что-то изменю — запущу не «python» «main.py», а что-нибудь другое, или установлю зависимости из другого файла — то предыдущие слои будут переиспользованы, как кеш.
Image — это упаковка контейнера, из образа запускаются контейнеры. Если смотреть на Docker с точки зрения пакетного менеджера (как будто мы работаем с deb или rpm-пакетами), то image — это по сути rpm-пакет. Через yum install мы можем поставить приложение, удалить его, найти в репозитории, скачать. Здесь примерно то же самое: из образа запускаются контейнеры, они хранятся в Docker registry (по аналогии с yum, в репозитории), и каждый image имеет хеш SHA-256, имя и тег.
Image собирается по инструкции из Dockerfile. Каждая инструкция из Dockerfile создаёт новый слой. Слои могут использоваться повторно.
Docker registry — это репозиторий образов Docker. По аналогии с ОС, у Docker есть общедоступный стандартный реестр — dockerhub. Но можно собрать свой репозиторий, свой Docker registry.
Container — то, что запускается из образа. По инструкции из Dockerfile собрали образ, затем мы его из этого образа запускаем. Этот контейнер изолирован от остальных контейнеров, он должен содержать в себе всё необходимое для работы приложения. При этом один контейнер — один процесс. Случается, что приходится делать два процесса, но это несколько противоречит идеологии Docker.
Требование «один контейнер — один процесс» связано с PID Namespace. Когда в Namespace запускается процесс с PID 1, если он вдруг умрёт, то весь контейнер тоже умирает. Если же там запущено два процесса: один живёт, а второй умер, то контейнер всё равно продолжит жить. Но это к вопросу Best Practices, мы про них поговорим в других материалах.
Более детально изучить особенности и полную программу курса можно по ссылке: «Видеокурс по Docker».
Автор: Марсель Ибраев, сертифицированный администратор Kubernetes, практикующий инженер в компании Southbridge, спикер и разработчик курсов Слёрм.
Docker: Окружение для тестирования
Последние пять лет принесли в нашу жизнь огромное количество технологий, с помощью которых можно быстро создавать изолированные окружения для разработки и тестирования. Но не смотря на это, организовать стабильное окружение для тестирования — далеко не самая простая задача. А если нужно тестировать сетевые взаимодействия компонентов и анализировать предельный уровень нагрузки на них, то задача становится еще сложнее. Добавив возможность быстрого развертывания окружения и гибкой настройки отдельных компонентов, мы сможем получить небольшой интересный проект.
В этой статье мы подробно расскажем о создании окружения на базе Docker контейнеров для тестирования нашего клиент-серверного приложения. При этом, если смотреть глобально, то данная статья будет хорошей иллюстрацией использования Docker и его ближайшей экосистемы.
Постановка задачи
Архитектура окружения для тестирования
Распределенную сетевую среду мы построили при помощи Docker контейнеров, изолирующих в себе наши и внешние сервисы, и docker-machine, которая позволяет организовать изолированное пространство для тестирования. В результате архитектура тестового окружения выглядит так:
Для визуализации окружения мы используем Weave Scope, так как это очень удобный и наглядный сервис для мониторинга Docker контейнеров.
С данным подходом удобно тестировать взаимодействие SOA компонентов, например, небольшие клиент-серверные приложения, подобные нашему.
Реализация базового окружения
Далее подробно рассмотрим каждый шаг создания тестового окружения на базе Docker контейнеров, с использованием docker-compose и docker-machine.
Начнем с docker-machine, которая позволит нам безболезненно выделить тестовое виртуальное окружение. При этом нам будет очень удобно работать с этим окружением напрямую с хост-системы.
Итак, создаем тестовую машину:
Эта команда создает VirtualBox VM с установленными внутри нее CoreOS и Docker, готовым к работе (Если вы используете Windows или MacOS, то рекомендуется установить Docker Toolbox, в котором уже все заложено. А если вы используете Linux, то необходимо поставить docker, docker-machine, docker-compose и VirtualBox самостоятельно). Мы рекомендуем ознакомиться со всеми возможностями docker-machine, это довольно мощный инструмент для управления окружениями.
Как видно из вывода этой команды, docker-machine создает все необходимое для работы с виртуальной машиной. После создания, виртуальная машина запущена и готова к работе. Давайте проверим:
Прекрасно, виртуальная машина запущена. Надо активировать доступ к ней в нашей текущей сессии. Вернемся на предыдущий шаг и внимательно посмотрим на последнюю строку:
Это autosetup для нашей сессии. Выполнив эту команду мы увидим следующее:
Это просто набор переменных окружения, который сообщит вашему локальному docker-клиенту где искать сервер. В последней строке расположена подсказка. Выполним эту команду и посмотрим на вывод команды ls :
В столбце ACTIVE наша активная машина помечена звездочкой. Обратите внимание, машина активна в рамках только текущей сессии. Мы можем открыть еще одно окно терминала и активировать там другую машину. Это может быть удобно для тестирования, например, оркестрации при помощи Swarm. Но это тема для отдельной статьи :).
Далее проверим наш docker-сервер:
Акцентируем внимание на OS/Arch, там всегда будет linux/amd64, так как docker-сервер работает в VM, нужно не забывать об этом. Немного отвлечемся и заглянем внутрь VM:
Да, это boot2docker, но интересно не это. Посмотрим на смонтированные разделы:
В данном случае мы используем MacOS и, соответственно, внутрь машины смонтирована директория /Users (аналог /home в linux). Это позволяет нам прозрачно работать с файлами на host-системе в рамках docker, то есть спокойно подключать и отключать volumes, не заботясь о прослойке в виде VM. Это действительно очень удобно. По идее, нам можно забыть про эту VM, она нужна только для того, чтобы docker работал в “родной” среде. При этом использование docker-клиента будет абсолютно прозрачным.
Итак, базовое окружение построено, далее будем запускать Docker контейнеры.
Настройка и запуск контейнеров
В этом файле все стандартно. Первым запускаем elasticsearch, как основное хранилище, затем три экземпляра с nginx, которые будут выступать поставщиками нагрузки. Далее запускаем наши сервер-приложения. Обратите внимание, все последующие контейнеры линкуются с предыдущими. В рамках нашей docker-сети, это позволит обращаться к контейнерам по имени. Чуть ниже, когда мы будем разбирать запуск нашего сервиса в “dual mode”, мы еще вернемся к этому моменту и рассмотрим его чуть подробнее. Также с первым контейнером, в котором находится экземпляр сервер-приложения, залинкованы агенты. Это означает, что все три агента будут пересылать логи именно этому серверу.
Наше приложение спроектировано таким образом, что для добавлении новой ноды в кластер, агенту или серверу достаточно сообщить об одном существующем узле кластера и он получит полную информацию о всей системе. В конфигурационных файлах для каждого экземпляра сервера мы укажем наш первый узел и агенты автоматически получат всю информацию о текущем состоянии системы. По прошествии некоторого времени после запуска всех узлов системы, мы просто выключим этот экземпляр. В нашем случае кластер переносит это безболезненно, вся информация о системе уже распространена между всеми участниками.
И еще один момент: обратите внимание на логику монтирования volumes. На контейнерах с nginx мы указываем именованный volume, который будет доступен в docker-сети, а на контейнерах с агентами мы просто подключаем его, указав имя сервиса. Таким образом, у нас получится shared volume между потребителями и поставщиками нагрузки.
Итак, запускаем наше окружение:
Проверяем, что все запустилось нормально:
Отлично, окружение поднялось, работает и все порты проброшены. В теории мы можем стартовать тестирование, но нам нужно доделать некоторые моменты.
Присвоение имен контейнерам
Генератор нагрузки крайне прост:
Стартовый скрипт тоже не сложный:
Вся хитрость будет заключаться в конфигурационном файле supervisord и запуске Docker-контейнера.
Рассмотрим конфигурационный файл:
Помимо нашей переменной, которую мы явно указали при старте контейнера, мы видим еще и все переменные, относящиеся к залинкованному контейнеру, а именно: IP-адрес, все открытые порты и все переменные, которые были явно установлены при сборке образа elasticsearch при помощи директивы ENV. Все переменные имеют префикс с именем экспортирующего контейнера и название, указывающее на их суть. Например, ELASTIC_PORT_9300_TCP_ADDR обозначает, что в переменной хранится значение, указывающее на контейнер с именем elastic и его ip-адрес, на котором открыт порт 9300. Если поднимать отдельный discovery-сервис для поставленных задач не резонно, то это отличный способ получить IP-адрес и данные залинкованных контейнеров. При этом остается возможность использовать их в своих приложениях, которые запущены в Docker контейнерах.
Управление контейнерами и система мониторинга
Итак, мы построили окружение для тестирования отвечающее всем нашим изначальным запросам. Осталась пара нюансов. Во-первых, установим Weave Scope (скриншоты которого были в начале статьи). При помощи Weave Scope можно визуализировать среду, в которой мы работаем. Помимо отображения связей и информации о контейнерах, мы можем выполнить attach к любому контейнеру или запустить полноценный терминал с sh прямо в браузере. Это незаменимые функции при отладке и тестировании. Итак, с хост-машины выполняем следующие действия, в рамках нашей активной сессии:
После выполнения этих команд, перейдя по адресу VM_IP:4040 мы попадаем в интерфейс управления контейнерами, представленный на картинке ниже:
Отлично, почти все готово. Для полного счастья нам не хватает системы мониторинга. Воспользуемся cAdvisor от Google:
Теперь по адресу VM_IP:8080 у нас есть система мониторинга ресурсов в реальном времени. Мы можем отслеживать и анализировать основные метрики нашего окружения, такие как:


