Для чего нужны контейнеры
Что такое облачные контейнеры и зачем они нужны
Gartner пишет, что через два года половина организаций мира будут использовать контейнерные технологии. Рассказываем, зачем они нужны.
Виртуализация — это разбиение аппаратного сервера на несколько виртуальных машин (ВМ). В результате вычислительные мощности распределяются между несколькими «пользователями».
Виртуализацией управляет программный компонент, называемый гипервизором. Он абстрагирует ВМ от аппаратного обеспечения, поэтому пользовательское приложение не знает, что работает в виртуальной среде.
Отсюда вытекает главное достоинство виртуализации: виртуальную машину можно без изменений переносить с одного сервера на другой вместе с операционной системой и приложениями.
В случае с контейнерами на отдельные компоненты разбивается не «железо», а операционная система. Контейнеры — это изолированная среда для приложения, в которой содержится все необходимое для его работы, например, программные библиотеки, файлы и метаданные.
Так как в контейнер помещается лишь одно приложение или функция, он весит намного меньше образа виртуальной машины и создается (запускается) быстрее. По этой причине их использует, к примеру, Spotify.
Контейнеры в инфраструктуре этого сервиса отвечают за добавление музыкальных композиций в плейлисты. Каждый контейнер-сервис при обращении к дата-центру компании выполняет одну задачу.
Первый узнает имя исполнителя, второй — скачивает обложку альбома, третий — текст песни и так далее. Такое «разделение обязанностей» помогает сервису обслуживать 70 млн пользователей. При этом все контейнеры изолированы друг от друга. Из-за своих небольших размеров они требуют меньше памяти и процессорной мощности, чем виртуальные машины. Они способны снизить нагрузку на серверы на 20–80%, по сравнению с ВМ.
Помимо Spotify контейнеры для разработки своих сервисов используют такие компании, как Yelp, Airbnb, Google, Microsoft, Lyft, eBay, PayPal и многие другие.
Есть и другие решения — Docker, Rancher, OpenShift и так далее.
Они нужны для гибкого масштабирования виртуальной инфраструктуры. Эти системы управляют «расписанием» (говорят, когда запускать тот или иной сервис) и распределяют нагрузку на серверы, чтобы вычислительные ресурсы расходовались равномерно.
Во время работы Kubernetes объединяет серверы в так называемый кластер — общую сеть, где «машины» могут взаимодействовать друг с другом. Один сервер выступает в роли «мозга» системы и управляет остальными «машинами» (их еще называют узлами). Узлы, получая инструкции от главного сервера, создают, удаляют и перемещают контейнеры.
Достоинством систем управления контейнерами является то, что вся эта «внутренняя кухня» скрыта от системного администратора или разработчика. Их задача — просто размещать контейнеры, а все остальное Kubernetes делает самостоятельно.
Но ряд особенностей работы таких систем все же приходится учитывать. Хотя контейнеры изолированы и не могут вмешиваться в работу друг друга, они делят между собой операционную систему. Поэтому важно убедиться, что код контейнерных приложений не мешает её работе.
Еще одной сложностью является безопасность таких систем. Один сервис может содержать множество контейнерных приложений, что создает больше «слабых точек», которыми могут воспользоваться злоумышленники. Шанс столкнуться с уязвимостью будет меньше, если у ОС и контейнеров будет только необходимый набор инструментов.
Настроить среду Kubernetes и организовать работу с контейнерами можно самостоятельно с нуля — для этого на GitHub, где лежит исходный код проекта, предоставлены все инструкции.
Что представляет собой контейнер?
Стандартизированная переносимая упаковка для приложений
Описание контейнеров
Точно так же, как судоходные компании используют физические контейнеры для изоляции различных грузов для транспортировки на судах и поездах, технологии разработки программного обеспечения все чаще используют концепцию, называемую контейнеризация.
Стандартный пакет программного обеспечения, известный как контейнер, объединяет код приложения с соответствующими файлами конфигурации, библиотеками и зависимостями, необходимыми для запуска приложения. Это позволяет разработчикам и ИТ-специалистам без проблем развертывать приложения в разных средах.
Для чего нужны контейнеры
Проблема неправильного запуска приложения при перемещении из одной среды в другую так же стара, как и сама разработка программного обеспечения. Такие проблемы обычно возникают из-за различий в требованиях базовой библиотеки конфигурации и других зависимостей.
Контейнеры позволяют решить эту проблему, предоставляя упрощенную неизменяемую инфраструктуру для упаковки и развертывания приложений. Приложение или служба, их зависимости и конфигурация упаковываются вместе в виде образа контейнера. Контейнерное приложение можно протестировать как модуль и развернуть в виде экземпляра образа контейнера в операционной системе узла.
Таким образом, контейнеры позволяют разработчикам и ИТ-специалистам развертывать приложения в разных средах с минимальными изменениями или вообще без них.
Узнайте больше о развитии и преимуществах контейнеров.
Контейнер и виртуальная машина
Виртуализация часто ассоциируется у пользователей с виртуальными машинами. На самом деле виртуализация может принимать множество форм, и контейнеры — одна из них. В чем же разница между виртуальными машинами и контейнерами?
В общем виртуальные машины виртуализируют базовое оборудование, чтобы на оборудовании могли работать несколько экземпляров операционной системы. Каждая виртуальная машина работает под управлением ОС и имеет доступ к виртуализированным ресурсам, представляющим базовое оборудование.
У виртуальных машин есть много преимуществ. К ним относятся возможность запуска различных операционных систем на одном сервере, более эффективное и экономичное использование физических ресурсов и ускоренная подготовка серверов. С другой стороны, каждая виртуальная машина содержит образ ОС, библиотеки, приложения и многое другое, поэтому ее размер может быть довольно большим.
Контейнер виртуализирует базовую ОС и заставляет контейнерное приложение «думать», что в нем самом есть операционная система, включая ЦП, память, хранилище файлов и сетевые подключения. Различия в базовой ОС и инфраструктуре абстрагированы (при условии, что базовый образ является согласованным), поэтому контейнер можно развернуть и запустить в любом расположении. Для разработчиков это очень большой плюс.
Так как контейнеры совместно используют операционную систему узла, им не нужно загружать или запускать библиотеки ОС. Это обеспечивает гораздо большую эффективность и простоту использования контейнеров. Контейнерные приложения могут запускаться за несколько секунд, а на компьютер может поместиться гораздо больше дополнительных экземпляров приложения по сравнению со сценарием с использованием виртуальной машины. Подход с совместно используемой ОС имеет дополнительное преимущество в виде снижения затрат, когда речь идет об обслуживании, например исправлении и установке обновлений.
Хотя контейнеры можно переносить, они ограничены операционной системой, для которой предназначены. Например, контейнер для Linux не может работать в Windows и наоборот.
Преимущества контейнеров
Динамичность
Когда разработчики создают и упаковывают свои приложения в контейнеры и предоставляют их ИТ-специалистам для запуска на стандартизированной платформе. Это сокращает общий объем работы по развертыванию приложений, а также позволяет упростить весь цикл разработки и тестирования. Кроме того, это повышает эффективность совместной работы и сотрудничества между группами разработки и эксплуатации, а также ускоряет доставку приложений.
Переносимость
Контейнеры предоставляют стандартизированный формат для упаковки и хранения всех компонентов, необходимых для запуска нужного приложения. Это позволяет решить распространенную проблему, условно называемую «у меня на компьютере это работает», а также обеспечивает переносимость между платформами ОС и облаками. Каждый раз, когда контейнер развертывается в каком-либо расположении, он выполняется в согласованной среде, которая остается неизменной от одного развертывания к другому. Теперь у вас есть единый формат, и его можно использовать на всех этапах — от разработки до запуска в производство.
Быстрое масштабирование
Так как использование контейнеров не влечет за собой издержек, характерных для виртуальных машин, включая отдельные экземпляры ОС, в одной и той же инфраструктуре может поддерживаться множество других контейнеров. Упрощенный характер контейнеров означает, что их можно быстро запускать и останавливать, а это позволяет быстро увеличивать и уменьшать масштаб.
Зачем и как использовать контейнеры: разбираемся с Docker, Kubernetes и другими инструментами
Цитируя разработчиков Docker, «контейнер — это стандартная единица программного обеспечения, в которую упаковано приложение со всеми необходимыми для его работы зависимостями — кодом приложения, средой запуска, системными инструментами, библиотеками и настройками».
Контейнеры используются уже более десяти лет и на сегодняшний день примерно четверть компаний-лидеров в сфере IT задействуют контейнерные решения в продакшене, а ещё столько же, согласно опросам, планировали приступить к этому в 2019-м году.
На рынке существует немало решений, представляющих среды запуска контейнеров и оркестрации, таких как CoreOS rkt, LXC, OpenVZ, containerd, Apache Mesos и Docker Swarm. Однако более 4/5 контейнеров запускается в среде Docker, а для оркестрации более половины пользователей выбрали Kubernetes. Об этих системах мы и поговорим.
Чем полезны контейнеры
Легковесность, быстродействие и возможность работать на высоком уровне абстракции, делегируя проблемы с железом и ОС провайдеру, — это преимущества контейнеров, позволяющие снизить операционные расходы, связанные с разработкой и эксплуатацией приложений, делающих решения на их базе столь привлекательными для бизнеса.
Техническим же специалистам контейнеры прежде всего полюбились за возможность упаковать приложение вместе с его средой запуска, решая тем самым проблему зависимостей в разных окружениях. Например, различие версий языковых библиотек на ноутбуке разработчика и в последующих окружениях рано или поздно приведёт к сбоям, и нужно будет как минимум потратить время на их анализ, а как максимум — решать проблему проникших в продакшен багов. Использование контейнеров устраняет проблему «А на моей машине все работало! ¯\_(ツ)_/¯».
Также контейнеры позволяют сократить время разработки приложения и упрощают управление им в продакшене благодаря лёгкости в настройке и изменении конфигурации, возможности версионировать её вместе с кодом приложения и удобным инструментам оркестрирования, позволяющим быстро масштабировать инфраструктуру. Кроме того, фактическое отсутствие привязки контейнеров к хостинговой платформе даёт огромную гибкость при выборе или смене провайдера — вы можете запускать их без принципиальных отличий в конечном результате на личном компьютере, bare metal серверах и в облачных сервисах.
Чем контейнеры отличаются от виртуальных машин
Наиболее частым вопросом при выборе среды запуска приложения является вопрос о различии между контейнерами и виртуальными машинами — двумя самыми популярными опциями на текущий момент. Между ними есть принципиальная разница. Контейнер, в сущности, является ограниченным внутри ОС пространством, использующим для доступа к аппаратным ресурсам ядро host-системы. ВМ представляет собой машину целиком со всеми необходимыми для её работы устройствами. Из этого образуются отличия, имеющие практическое значение:
Основные принципы контейнеризации приложений
Для эффективной работы приложения в контейнерах недостаточно просто создать образ контейнера и запустить его. Нужно позаботиться о том, чтобы архитектура приложения и контейнера соответствовала базовым принципам контейнеризации, которые хорошо изложила компания RedHat.
1 контейнер — 1 сервис
Контейнер должен выполнять только одну функцию — не следует помещать в него все сущности, от которых зависит приложение. Следование этому принципу позволяет добиться большей переиспользуемости образов и, что самое главное, позволяет более тонко масштабировать приложение — узким местом вашего сервиса может оказаться только какая-то часть используемого стэка технологий, и разведение всех его частей по разным контейнерам позволит точечно увеличивать производительность вашего сервиса.
Неизменность образа
Все изменения внутри контейнера должны вноситься на стадии сборки образа — соблюдение этого принципа страхует вас от утраты данных при уничтожении контейнера. Неизменность контейнера также даёт возможность выполнять параллельные задачи в CI/CD системах — например, можно одновременно запустить разного рода тестирования, ускоряя тем самым процесс разработки продукта.
Утилизируемость контейнеров
Этот принцип являет собой яркий пример современной концепции «Обращайся с инфраструктурой как со скотом, не как с питомцами». Это значит, что любой контейнер может быть в любой момент уничтожен и заменён на другой без остановки обслуживания. Конфигурация контейнера в виде его образа сущностно отделена от непосредственно выполняющего работу экземпляра контейнера, что позволяет «пускать под нож» экземпляры, когда потребуется — при сбое проверки состояния контейнера, масштабировании на понижение и т. д. Соответствие этому принципу означает, что выход контейнеров из строя не должен быть новостью для вашего приложения: ротация контейнеров должна стать одним из требований к разработке.
Отчётность
Контейнер должен иметь точки проверки состояния его готовности (readiness probe) и жизнеспособности (liveness probe), предоставлять логи для отслеживания состояния запущенного в нём приложения.
Управляемость
Приложение в контейнере должно иметь возможность взаимодействовать с контролирующим его процессом — например для корректного завершения своей работы по команде извне. Это позволит аккуратно закрывать транзакции, препятствуя потере пользовательских данных в результате остановки или уничтожения контейнера.
Самодостаточность
Образ с приложением должен обладать всеми необходимыми зависимостями для работы — библиотеками, конфигами и прочим. Сервисы же к этим зависимостям не относятся, иначе это противоречило бы принципу «1 контейнер — 1 сервис». Связность контейнеров, зависящих друг от друга, можно определить с помощью инструментов оркестрирования, о чём будет рассказано ниже.
Лимитирование ресурсов
К лучшим практикам эксплуатации контейнеров относится настройка ресурсных лимитов (CPU и RAM): следование этой практике позволяет сохранять внимательное отношение к экономии ресурсов и вовремя реагировать на их избыточное потребление.
Docker
Когда мы говорим о контейнерах в современных IT-системах, прежде всего мы подразумеваем Docker — open-source-технологию, благодаря своей популярности ставшую в IT синонимом слова «контейнер».
Основные сущности Docker
Dockerfile
Текстовый файл, используемый для создания образа контейнера. Содержит в себе ссылку на базовый образ, служащий отправной точкой при формировании нового образа и набор инструкций для сборки, таких как установка зависимостей, компиляция приложения и копирование конфигов. Также он содержит точку входа в контейнер — команду, выполняемую при его запуске.
Image
Готовая файловая система, сформированная по инструкциям из Dockerfile и служащая прообразом для запускаемых контейнеров.
Instance
Запущенный экземпляр образа, минимальная единица деплоя в Docker.
Volume
Подключаемая к контейнерам файловая система, не являющаяся их неотъемлемой частью и существующая независимо от образа. С помощью объектов Volume решается проблема сохранности данных, записанных в процессе работы контейнеров в локальной файловой системе после их уничтожения.
Registry
Репозиторий, используемый для хранения Docker-образов. Registry может быть как публичным, так и приватным, защищённым механизмом аутентификации.
Процесс разработки в среде Docker
Типичный процесс разработки в среде Docker выглядит следующим образом: разработчики устанавливают на свои машины Docker, загружают собранный заранее образ с установленной средой сборки и выполнения приложения, а затем запускают контейнер командой, которая также пробросит в него директорию с исходниками. Для установки Docker не требуется особого железа — он может быть установлен на вполне заурядной машине. Однако у него имеются ограничения по версиям ОС — Windows 7 64bit или выше для ПК с поддержкой Hyper-V, macOS Sierra 10.12 для устройств от Apple и версией ядра 3.10 для систем с Linux. Контейнеры Docker являются родной технологией для ОС Linux и запускаются на других с помощью виртуальных машин под её управлением.
Инструкции по установке Docker на разных платформах: Windows, Mac, Linux Ubuntu.
Чтобы запустить ваш первый контейнер на Docker, после его установки введите в командной строке docker run hello-world — эта команда загрузит образ hello-world с Docker hub’а (публично доступный Docker registry), создаст контейнер, используя этот образ, и выдаст приветственную фразу:
Hello from Docker!
This message shows that your installation appears to be working correctly.
.
Оркестрирование контейнеров: Kubernetes
Оркестрирование — это в высокой степени автоматизированный процесс управления связанными сущностями, такими как группы виртуальных машин или контейнеров.
Kubernetes (также встречается в виде акронима K8s) — это совокупность сервисов, реализующих контейнерный кластер и его оркестрирование. Kubernetes не заменяет Docker — он серьёзно расширяет его возможности, упрощая управление развертыванием, сетевой маршрутизацией, расходом ресурсов, балансировкой нагрузки и отказоустойчивостью запускаемых приложений.
NetApp Kubernetes Service позволит создать cloud-agnostic кластер с уже реализованными механизмами деплоя и управления жизненным циклом приложения, автоматическим масштабированием инфраструктуры, интеграцией с сервисами хранилищ данных и многим другим, снизив затраты на конфигурацию и поддержку сложной инфраструктуры.
Основные сущности, которыми оперирует Kubernetes
Node (master и slave)
Узлы, из которых состоит кластер Kubernetes. Master-нода осуществляет контроль над кластером через планировщик и менеджер контроллеров, обеспечивает интерфейс взаимодействия с пользователями посредством API-сервера и содержит хранилище etcd, где находится конфигурация кластера, статусы его объектов и метаданные. Slave-нода предназначена исключительно для запуска контейнеров, для этого на ней установлены два сервиса Kubernetes — сетевой маршрутизатор и агент планировщика.
Namespace
Структурный объект, позволяющий разграничивать ресурсы кластера между пользователями и командами.
Минимальная единица развёртывания в Kubernetes, группа из одного или более контейнеров, собранных для совместного деплоя на ноде. Группировать контейнеры разного вида в Pod имеет смысл, когда они зависят друг от друга и потому должны быть запущены на одной ноде, чтобы сократить время отклика при их взаимодействии. Пример — контейнеры с веб-приложением и кэширующим его сервисом.
ReplicaSet
Объект, описывающий и контролирующий соответствие запущенного на кластере количества реплик Pod’ов. Установка количества реплик больше одной требуется для повышения отказоустойчивости и масштабирования приложения. Общепринято создавать ReplicaSet с помощью Deployment.
Deployment
Объект, декларативно описывающий Pod’ы, количество реплик и стратегию их замены при обновлении параметров.
StatefulSet
Действует по тому же принципу, что и ReplicaSet, однако дополнительно позволяет описывать и сохранять при перезапуске уникальный сетевой адрес Pod’ов или их дисковое хранилище.
DaemonSet
Объект, обеспечивающий контроль за тем, что на каждой ноде (или нескольких выбранных) будет запущено по экземпляру указанного Pod’а.
Job и CronJob
Объекты, запускающие соответственно однократно и регулярно по расписанию указанный Pod и отслеживающие результат завершения его работы.
Label и Selector
Метки, позволяющие маркировать ресурсы и тем самым упрощать групповые манипуляции, связанные с ними.
Service
Инструмент для публикации приложения в качестве сетевого сервиса, в том числе реализующий балансировку нагрузки между Pod’ами приложения.
Если сравнить объекты Docker и Kubernetes, то станет понятна разница в задачах, решаемых этими инструментами: можно сказать, что Docker управляет контейнерами, в то время как Kubernetes управляет самим Docker.
Управление конфигурацией (Configuration/Complexity Management)
Развитие IT-систем ведёт ко всё большему их усложнению, и это порождает проблемы управления — даже на небольшом количестве серверов или контейнеров ручное управление приложением превращает практически любое изменение конфигурации в трудовой подвиг, а на десятках или сотнях делает его абсолютно невозможным. К счастью, новые проблемы ведут и к новым решениям — в этом разделе мы расскажем о некоторых инструментах управления конфигурацией (configuration management) или, как ещё принято говорить, управления сложностью (complexity management). Они используются для установки, управления и обновления приложений Kubernetes: например, с их помощью можно описать приложение, состоящее из фронтенда, бэкенда и всех необходимых для их работы сервисов, таких как объекты Kubernetes, контейнеры с веб-серверами, базами данных, серверами очередей и т. д.
Перечисленные в этом разделе инструменты обладают обширными сообществами и множеством готовых пользовательских конфигураций, что поможет сэкономить массу времени при начальной настройке сервисов, переиспользуя и адаптируя уже написанный другими пользователями код.
Kustomize
Благодаря популярности у пользователей и своей простоте, начиная с версии Kubernetes 1.14, Kustomize является встроенным инструментом управления конфигурацией. Для описания приложений использует чистый язык разметки YAML без возможности шаблонизации и использования параметров, что является одновременно его сильной и слабой сторонами, упрощая процесс настройки и вместе с тем сильно его ограничивая.
Ansible
Многофункциональный инструмент, для которого конфигурация Kubernetes-приложений — лишь одно из великого множества применений, реализованная с помощью специального модуля интеграции. Например, Ansible может быть использован для настройки виртуальных машин, развертывания облачной инфраструктуры, выполнения бэкапов и т.д. Его универсальность позволяет решать разнообразные задачи, связанные с IT-проектами, одним инструментом — но ценой меньшей функциональности в отношении управления конфигурацией приложений Kubernetes. Для описания использует YAML и язык шаблонов Jinja2.
Управляйте хранилищами данных в автоматизированном режиме с помощью модулей интеграции Ansible NetApp.
Jsonnet
Также как и Ansible, Jsonnet не является чем-то специфичным для Kubernetes, однако многие знакомы с ним именно благодаря K8s. Jsonnet описывает объекты с помощью расширенного JSON, включающего комментарии, текстовые блоки, параметры, переменные, условные включения и функции. Очень мощный и гибкий инструмент.
Пакетный менеджер приложений Kubernetes. Этот инструмент описывает приложения в виде декларативных диаграмм (charts), создающихся с помощью языка разметки YAML и шаблонов Golang. Helm обладает широкой базой готовых диаграмм, даёт возможность версионировать конфигурации и переключаться между версиями релизов, т. е. откатывать конфигурацию. Из всех приведенных здесь инструментов является наиболее функциональным в отношении управления приложениями Kubernetes и одновременно обладает наиболее сложным способом описания конфигурации из-за шаблонов Golang, весьма требователен к пользовательским навыкам.
В этой статье перечислены лишь те инструменты, что наиболее заслуживают внимания по нашему мнению. Помимо них существует ещё с добрый десяток решений для задач управления конфигурацией в Kubernetes: такие как Kapitan, Ksonnet, Replicated Ship и т. д. При выборе менеджера управления конфигурацией мы рекомендуем определиться с требованиями, предъявляемыми к нему, и руководствоваться принципом разумной достаточности, не используя без нужды излишне сложный инструмент — хорошим путем будет начать с чего-то простого, дополнительно задействуя более мощный инструмент, когда возникнет необходимость.
Платформы для хостинга контейнеров
Одним из основных моментов при выводе в продакшен контейнерного приложения является выбор того, где же в конечном счёте это приложение будет запущено. В этой части статьи мы постараемся помочь вам, описав два основных на сегодняшний день варианта, их сильные и слабые стороны.
Своё железо (bare metal)
Этот подход можно назвать консервативным — выбрав его, вы покупаете или арендуете серверы, нанимаете специалистов и строите свой собственный кластер. Очевидные его плюсы — тонкая настройка, возможность полного контроля над инфраструктурой и, как следствие, превосходящая производительность с более высокой отдачей от бюджета в долгой перспективе. Из минусов можно отметить большие финансовые (в том числе капитальные) и временные затраты на конфигурацию и поддержку, а также зависимость от специалистов по её поддержке. Как правило, этот вариант выбирают компании, имеющие выверенные долгосрочные планы, уже обеспеченные солидным бюджетом.
Облачные решения (SaaS)
Крупные облачные провайдеры предоставляют своим клиентам сервисы для запуска контейнеров — готовые среды, обёрнутые удобным интерфейсом управления. Построенные по такому принципу решения называются Software as a Service (SaaS). Они не требуют никаких капитальных затрат, поскольку вся инфраструктура арендуется, а конфигурация создаётся в минимальном объёме, относящемуся исключительно к запускаемому приложению. Сами же кластеры настраиваются провайдером по указанному пользователем небольшому объему параметров. SaaS-решения — оптимальный вариант для стартап-компаний, небольших и развивающихся проектов. Самым большим минусом этого решения можно назвать повышенную в сравнении с bare metal стоимость при условии многолетнего использования.
Хотите обеспечить максимальную сохранность данных, создаваемых и используемых в контейнерах? NetApp Trident позволит легко интегрировать в вашу контейнерную инфраструктуру надежное и функциональное хранилище данных enterprise-уровня.
Заключение
Ещё недавно не смолкали дебаты на тему оправданности использования контейнеров в продакшене, то и дело были слышны обвинения в их ненадежности. Однако время не стоит на месте, индустрия оценила их перспективность, сделала свой выбор, и инвестиции в контейнерные решения потекли широкой рекой, с каждым днем делая решения на их базе всё удобнее и привлекательнее. На сегодняшний день примитивную настройку кластера и деплой приложений в него можно выполнить используя один лишь веб-интерфейс, предварительно прочитав несколько страниц документации — настолько это стало просто. А их низкая по сравнению с виртуальными машинами стоимость откусывает у ВМ всё большую долю рынка, забирая то, что не требует для своей работы специфики устройства ВМ. Безусловно, контейнеры зарекомендовали себя как жизне- и конкурентоспособное решение, сокращающее время вывода продукта на рынок, стоимость его разработки и эксплуатации.
Рассказывает Сергей Бродин. Текст подготовили вместе с NetApp