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

Containers

5 самых популярных вопросов при внедрении service mesh в корпорации на примере Istio

19.06.2020 14:16:52 | Автор: admin
Не только на мировом, но и на российском рынке можно заметить волну интереса к технологиям сервисных сеток, или service mesh. Ниже под катом мы разберемся, какие задачи эта технология решает, как она развивалась, а также с какими вопросами сталкиваются корпорации при адаптации Istio у себя в ИТ-инфраструктуре.

image


Мое знакомство с service mesh было во многом случайным, когда в 2017 году мне на глаза попался анонс о сотрудничестве Google и IBM по созданию нового open source проекта. Не сказать, что партнерства крупнейших технологических компаний редки, но именно этот случай вызвал у меня большой интерес. Во-первых, примеров взаимодействия именно компаний Google и IBM все же не так много: пожалуй, наиболее известными фактами будут работа вокруг открытой аппаратной архитектуры OpenPOWER, а также наличие сервисов IBM в Google Cloud. Во-вторых, несмотря на наличие примеров, когда и Google, и IBM развивают один и тот же open source проект (Kubernetes или TensorFlow), случаев, чтобы обе эти компании стали именно основателями проекта, очень мало, и они достаточно уникальны. И, в-третьих, наличие среди основателей проекта IBM и Google компании Lyft конкурента Uber как сервиса вызова такси, вызывало вопросы и неподдельный интерес. Тот анонс в 2017 году рассказывал о выпуске технологии Istio, предназначенной для управления взаимодействием различных сервисов. Поначалу не совсем очевидно, в чем заключается проблема и зачем создавать такой проект, так как подходов по управлению взаимодействием между сервисами было известно довольно много. Чтобы понять проблематику, стоит взглянуть на ситуацию шире и посмотреть на изменения в ИТ-архитектуре на тот момент времени.

Что такое service mesh


Причины появления и столь стремительно нарастающей популярности service mesh неразрывно связаны с изменениями в ИТ архитектуре. Представить появление service mesh без микросервисной архитектуры достаточно сложно давайте посмотрим почему. Можно долго спорить, что такое микросервисная архитектура, так как единого и устоявшегося определения нет (и вообще эта тема заслуживает отдельной статьи), но для упрощения остановимся на следующих ключевых характеристиках: это небольшие автономные части бизнес-логики, реализованные как сервисы, каждый из которых имеет свой цикл сборки и поддержки. В таком случае логично задуматься о том, как эти небольшие сервисы будут взаимодействовать друг с другом и как контролировать этот процесс. Здесь и появляется service mesh. В реальной жизни эту технологию можно сравнить с дорожным навигатором. На дорогах могут случаться различные ситуации: аварии, заторы, выход из строя светофоров, а система позволяет вам добраться из пункта А в пункт Б наиболее оптимальным способом, зная обо всех произошедших событиях.

Ключевыми задачами, которые берет на себя service mesh, являются:
  • управление трафиком
  • балансировка нагрузки
  • обеспечение безопасности при взаимодействии сервисов
  • сбор метрик и мониторинг

Другим аналогом service mesh из реальной жизни может быть служба почтовой доставки: она решает, что делать с посылкой, если вас нет дома или вы переехали, следит за безопасностью транспортировки, обеспечивает приватность передачи посылки и отслеживает статусы.

Эволюция развития service mesh


В настоящее время service mesh стал отдельным слоем и во многом стандартом де-факто современной ИТ-архитектуры на уровне инфраструктуры. Можно ли строить современные решения без service mesh и реализовывать этот функционал как-то по-другому? Конечно, да, только вопрос в удобстве, гибкости, времени реализации и дальнейшей поддержке решения. Безусловно, задачи, связанные с управлением трафика или балансировкой, можно решить самому на уровне кода для каждого из сервисов. Но так как микросервисная архитектура подразумевает существование десятков, сотен или даже тысяч различных сервисов, то реализовывать один и тот же функционал при разработке каждого из них совсем не удобно. Зачем разрабатывать один и тот же функционал десятки или сотни раз, если можно вынести его отдельно?
Первые реализации service mesh были сделаны на прикладном уровне. Самый известный пример фреймворк (или набор библиотек) Netflix OSS, доступный для использования с 2012 года. В него вошли компоненты, реализующие функционал, присущий service mesh: с помощью Eureka производится обнаружение сервисов (service discovery), с помощью Hystrix ряд паттернов обнаружений ошибок (circuit breaker), Zuul решает задачи динамической маршрутизации (dynamic routing).

На необходимость изменения этого подхода оказали сильное влияние следующие факторы:
  • поддержка нескольких языков программирования и отсутствие зависимости от них
  • удобство разделения прикладных и инфраструктурных задач для DevOps: возможность вносить изменения в прикладной код без влияния на инфраструктуру
  • развитие контейнерных технологий

Как ни крути, Netflix OSS куда больше был интегрирован в прикладную логику сервиса, требовал использование стека технологий Netflix, имел зависимость библиотек от языка разработки и не был заточен для использования в контейнерах.
Istio как пример следующей волны эволюции технологии использует sidecar (Envoy от Lyft), то есть прокси, который располагается рядом с каждым сервисом и берет на себя функционал по управлению политиками безопасности, трафиком, сбор телеметрии и пр. Это позволяет быть нейтральным к выбору языка программирования, иметь хорошую интеграцию с Kubernetes как стандарта де-факто по оркестрации контейнерных сред и не иметь никаких зависимостей от прикладной логики сервисов. По факту именно на этом шаге эволюции технологии service mesh произошло ее окончательное выделение в отдельный инфраструктурный слой как самостоятельный уровень современной ИТ-архитектуры.

Адаптация технологии в корпоративном мире


Все большая популярность микросервисной архитектуры и контейнерных технологий и те преимущества, которые они дают, не оставили в стороне большие российские корпорации, которые начали задумываться об использовании этих подходов у себя. Вместе с этим возникает ряд вопросов по использованию service mesh и, в частности, Istio. Многие сомневаются в том, что технология достаточно зрелая для использования в корпоративном мире, что обладает достаточным функционалом и способна выдерживать большие нагрузки. Ниже будут даны ответы на пять наиболее популярных вопросов, которые нам задавали ИТ сотрудники корпораций про использование Istio, чтобы помочь убедиться в ее готовности к внедрению.

image

Вопрос 1: Достигла ли технология Istio достаточной зрелости для внедрения в корпорациях?


Так как мы говорим о крупных организациях, то для них вопрос зрелости той или иной технологии является одним из самых первых. Что подразумевается под зрелостью? Параметрами зрелости могут быть функциональность, стабильность работы, количество промышленных внедрений, максимальная нагрузка, а также соответствие ряду нефункциональных требований, например, по отказоустойчивости или масштабированию. Важно понимать, что для каждой компании количественные значения каждого из параметров будут своими в зависимости от ее масштабов и сценариев использования.
Что можно сказать про Istio? С точки зрения стабильности работы в мире open source немаловажным является выпуск версии 1.0, которая сообществом контрибьюторов Istio была представлена еще летом 2018 года. Примерами по использованию технологии являются уже десятки компаний, наиболее известными среди которых являются Ebay, Yahoo и банк ING. Интересными примером является история использования Istio при эксплуатации истребителя F16. Отдельно стоит выделить факт, что ведущие облачные провайдеры IBM и Google предоставляют сервисы на базе Istio для своих клиентов. Более того, Istio используется даже как часть новых open source фреймворков. Пример: Kabanero, направленный на более быструю разработку приложений поверх контейнерной инфраструктуры.

С точки зрения нефункциональных требований в корпорациях уделяется большое внимание требованиям по отказоустойчивости, и здесь Istio предоставляет большое число опций по развертыванию, как внутри одного, так и нескольких кластеров Kubernetes. Ниже в статье мы рассмотрим вопрос об опциях развертывания подробнее. Думаю, излишне говорить, что все эти аргументы однозначно позволяют судить о том, что Istio как технология достигла достаточного уровня зрелости для внедрения в корпоративном сегменте для решения бизнес-критичных задач.

Вопрос 2: Service mesh для новых сред с контейнерами, а что делать с традиционным ландшафтом на виртуальных машинах?


Service mesh принадлежит типу технологий, относящихся к cloud native, которые создавались в эру развития контейнеров. Но, вспоминая реальность ИТ ландшафта корпораций, можно заметить, что промышленных систем, работающих поверх контейнеров не так много, и корпорации стоят лишь в начале пути по их массовому использованию. Многие бизнес-критичные задачи по-прежнему работают на виртуальных машинах и здесь возникает вопрос: неужели для них нельзя использовать Istio?
Краткий ответ конечно, можно. Istio позволяет создавать разные конфигурации с использованием как контейнерной инфраструктуры, так и виртуальных машин или даже bare metal. Для связи виртуальных машин и service mesh необходимо выполнить ряд действий, например обеспечить видимость IP-адресов кластера с Istio и пр. Более подробное описание и примеры можно найти здесь.

Вопрос 3: Какую модель развертывания выбрать?


Этот вопрос, между прочим, весьма непростой и затрагивающий много областей, включая как технические вещи (нефункциональные требования по отказоустойчивости, безопасности и производительности), так и организационные (структуру команд). Какие опции развертывания возможны?
  • один или несколько кластеров (мультикластер)
  • один или несколько сетевых сегментов
  • одна или несколько контрольных точек управления (control panel)
  • одна или несколько сеток (mesh)

На текущий момент времени можно сказать, что опция мультикластерного развертывания является наиболее востребованной в корпорациях среди прочих не случайно этому аспекту уделяется большая часть работы сообщества вокруг проекта Istio. Каковы причины выбора именно этой опции? Это наличие большого количества команд разработки отдельных продуктов и систем, это необходимость развертывания в нескольких ЦОД, это разделение на зоны разработки, тестирования и промышленной эксплуатации. Из-за всех этих требований опция развертывания одного кластера даже с несколькими сервисными сетками внутри него не позволяет обеспечить необходимый уровень изоляции ресурсов.
Безусловно, внутри мультикластерного развертывания могут быть также варианты размещения контрольных панелей: не обязательно размещать одну контрольную панель на один кластер, несколько кластеров могут использовать одну контрольную панель.
На практике на определение опции развертывания уходит не одна неделя проектирования, так как архитекторам необходимо прийти к компромиссу между хорошим уровнем изоляции ресурсов и накладными расходами на взаимодействие между кластерами.

Вопрос 4: А какую нагрузку выдержит?


Так как речь идет о корпорациях, то, как правило, они обслуживают большое число клиентов и, соответственно, имеют на своих системах большие нагрузки. Поэтому вопрос абсолютно не праздный и на практике не редки случаи, когда та или иная новая технология не давала нужную производительность и не могла обеспечить предоставление сервисов компании по запросу клиентов.
Конечно, самый грамотный ответ на этот вопрос: зависит от множества факторов. То, как развернута система, какие требования по отказоустойчивости или изоляции, какая версия технологии используется все эти факторы оказывают прямое воздействие на производительность. Но вряд ли этот ответ способен дать хоть какие-то оценки, поэтому посмотрим на уже имеющийся опыт других компаний. К сожалению, в открытых источниках сложно найти детальную информацию от компаний по их опыту использования Istio, но на различных встречах, митапах или конференциях уже в начале 2019 года одной из компаний в области информационной безопасности были представлены цифры в десятки тысяч транзакций в секунду (TPS) системы, использующей Istio. Многие корпорации провели пилотные проекты и получили результаты в несколько сотен транзакций в секунду. Много это или мало? Для примера, только несколько крупных банков России имеют нагрузки в несколько тысяч TPS на своих ИТ системах, поэтому оценка даже в несколько сотен TPS с лихвой покроет подавляющее большинство задач любой корпорации.

Вопрос 5: Когда будут нужные нам фичи?


Во время внедрения Istio технические специалисты организаций часто обращаются в IBM как к компании-основателю проекта с вопросами о сроках реализации конкретных новых фич технологии.

На этом вопросе можно хорошо показать разницу между проприетарным программным обеспечением от какого-либо вендора и миром open source. Многие корпорации с точки зрения своих ожиданий одинаково относятся и к тем, и другим технологиям, хотя в ряде моментов различия достаточно большие и ждать такой же ответственности от участников open source проекта, как от компании-производителя коммерческого ПО, странно. Безусловно, за большинством успешных open source проектов стоит одна или несколько компаний, которая, как правило, и является основателем. Но в отличие от коммерческого ПО, компания-основатель не может просто так взять и добавить фичу в проект без обратной связи от других контрибьюторов. Здесь есть и свои плюсы, и минусы. Бывали случаи, когда один из контрибьюторов брался за реализацию конкретной фичи, в которой были заинтересованы многие участники проекта, но срывал сроки из-за занятости и болезни, отодвигая релиз на несколько месяцев вперед. Поэтому в случае open source проекта гарантировать выход конкретной фичи в конкретный срок намного тяжелее, чем в случае с коммерческим ПО. С другой стороны, нет такой прямой зависимости от решения одной компании, так как реализацию может взять на себя другой участник проекта.

Поэтому четкого ответа на этот вопрос не существует, но есть ряд рекомендаций, которые позволят держать руку на пульсе происходящего в open source проекте. На примере Istio cписок рабочих групп проекта известен, их встречи и протоколы обсуждений открыты, доступна возможность задавать вопросы и описывать проблемы во всех этих, а также многих других вещах представители корпораций могут участвовать. В текущий момент времени корпорации крайне осторожно принимают участие в жизни сообщества, и очень хочется надеяться, что в ближайшее время этот тренд изменится.

Вместо заключения



Что можно сказать в итоге? Несмотря на то, что Istio достаточно молодая технология, ее текущий уровень зрелости и существующий функционал полностью отвечают требованиям корпораций. Видно, что среди крупных российских компаний интерес к Istio за последний год существенно вырос и все больше и больше ИТ команд начинают свои первые проекты, а ряд из них уже использует технологию в промышленной среде.
Для тех, кто хочет видеть Istio не только в своих ИТ системах, но и на полке или столе, мой коллега создал модель парусника как копию логотипа Istio для распечатки на 3D-принтере, которую можно скачать здесь.
Подробнее..

Перевод Что такое CICD? Разбираемся с непрерывной интеграцией и непрерывной поставкой

13.08.2020 22:14:38 | Автор: admin
В преддверии старта курса CI/CD на AWS, Azure и Gitlab подготовили для вас перевод полезного материала.



Непрерывная интеграция (Continuous Integration, CI) и непрерывная поставка (Continuous Delivery, CD) представляют собой культуру, набор принципов и практик, которые позволяют разработчикам чаще и надежнее развертывать изменения программного обеспечения.

CI/CD это одна из DevOps-практик. Она также относится и к agile-практикам: автоматизация развертывания позволяет разработчикам сосредоточиться на реализации бизнес-требований, на качестве кода и безопасности.

Определение CI/CD


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

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

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

Инструменты CI/CD помогают настраивать специфические параметры окружения, которые конфигурируются при развертывании. А также CI/CD-автоматизация выполняет необходимые запросы к веб-серверам, базам данных и другим сервисам, которые могут нуждаться в перезапуске или выполнении каких-то дополнительных действий при развертывании приложения.

Непрерывная интеграция и непрерывная поставка нуждаются в непрерывном тестировании, поскольку конечная цель разработка качественных приложений. Непрерывное тестирование часто реализуется в виде набора различных автоматизированных тестов (регрессионных, производительности и других), которые выполняются в CI/CD-конвейере.

Зрелая практика CI/CD позволяет реализовать непрерывное развертывание: при успешном прохождении кода через CI/CD-конвейер, сборки автоматически развертываются в продакшн-окружении. Команды, практикующие непрерывную поставку, могут позволить себе ежедневное или даже ежечасное развертывание. Хотя здесь стоит отметить, что непрерывная поставка подходит не для всех бизнес-приложений.

Непрерывная интеграция улучшает коммуникации и качество


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

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

Многие используют фича-флаги (feature flag) механизм для включения и выключения функционала в рантайме. Функционал, который еще находится в стадии разработки, оборачивается фича-флагами и развертывается из master-ветки в продакшн, но отключается до тех пор, пока не будет полностью готов к использованию. По данным недавнего исследования 63 процента команд, использующих фича-флаги, говорят об улучшении тестируемости и повышении качества программного обеспечения. Для работы с фича-флагами есть специальные инструменты, такие как CloudBees Rollout, Optimizely Rollouts и LaunchDarkly, которые интегрируются в CI/CD и позволяют выполнять конфигурацию на уровне фич.

Другой способ работы с фичами использование веток в системе контроля версий. В этом случае надо определить модель ветвления (например, такую как Gitflow) и описать как код попадает в ветки разработки, тестирования и продакшена. Для фич с длительным циклом разработки создаются отдельные фича-ветки. После завершения работы над фичей разработчики сливают изменения из фича-ветки в основную ветку разработки. Такой подход работает хорошо, но может быть неудобен, если одновременно разрабатывается много фич.

Этап сборки заключается в автоматизации упаковки необходимого программного обеспечения, базы данных и других компонент. Например, если вы разрабатываете Java-приложение, то CI упакует все статические файлы, такие как HTML, CSS и JavaScript, вместе с Java-приложением и скриптами базы данных.

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

Большинство CI/CD-инструментов позволяет запускать сборку вручную, по коммиту или по расписанию. Командам необходимо обсудить расписание сборки, которое подходит для них в зависимости от численности команды, ожидаемого количества ежедневных коммитов и других критериев. Важно, чтобы коммиты и сборка были быстрыми, иначе долгая сборка может стать препятствием для разработчиков, пытающихся быстро и часто коммитить.

Непрерывное тестирование это больше, чем автоматизация тестирования


Фреймворки для автоматизированного тестирования помогают QA-инженерам разрабатывать, запускать и автоматизировать различные виды тестов, которые помогают разработчикам отслеживать успешность сборки. Тестирование включает в себя функциональные тесты, разрабатываемые в конце каждого спринта и объединяемые в регрессионные тесты для всего приложения. Регрессионные тесты информируют команду: не сломали ли их изменения что-то в другой части приложения.

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

Регрессионные тесты это только начало. Тестирование производительности, тестирование API, статический анализ кода, тестирование безопасности эти и другие виды тестирования тоже можно автоматизировать. Ключевым моментом является возможность запуска этих тестов из командной строки, через веб-хук (webhook) или через веб-сервис и возврат результата выполнения: успешный был тест или нет.

Непрерывное тестирование подразумевает не только автоматизацию, но и интеграцию автоматического тестирования в конвейер CI/CD. Модульные и функциональные тесты могут быть частью CI и выявлять проблемы до или во время запуска CI-конвейера. Тесты, требующие развертывания полного окружения, такие как тестирование производительности и безопасности, часто являются частью CD и выполняются после разворачивания сборок в целевых средах.

CD-конвейер автоматизирует поставку изменений в различные окружения


Непрерывная поставка это автоматическое развертывание приложения в целевое окружение. Обычно разработчики работают с одним или несколькими окружениями разработки и тестирования, в которых приложение развертывается для тестирования и ревью. Для этого используются такие CI/CD-инструменты как Jenkins, CircleCI, AWS CodeBuild, Azure DevOps, Atlassian Bamboo, Travis CI.

Типичный CD-конвейер состоит из этапов сборки, тестирования и развертывания. Более сложные конвейеры включают в себя следующие этапы:

  • Получение кода из системы контроля версий и выполнение сборки.
  • Настройка инфраструктуры, автоматизированной через подход инфраструктура как код.
  • Копирование кода в целевую среду.
  • Настройка переменных окружения для целевой среды.
  • Развертывание компонентов приложения (веб-серверы, API-сервисы, базы данных).
  • Выполнение дополнительных действий, таких как перезапуск сервисов или вызов сервисов, необходимых для работоспособности новых изменений.
  • Выполнение тестов и откат изменений окружения в случае провала тестов.
  • Логирование и отправка оповещений о состоянии поставки.


Например, в Jenkins конвейер определяется в файле Jenkinsfile, в котором описываются различные этапы, такие как сборка (build), тестирование (test) и развертывание (deploy). Там же описываются переменные окружения, секретные ключи, сертификаты и другие параметры, которые можно использовать в этапах конвейера. В разделе post настраивается обработка ошибок и уведомления.

В более сложном CD-конвейере могут быть дополнительные этапы, такие как синхронизация данных, архивирование информационных ресурсов, установка обновлений и патчей. CI/CD-инструменты обычно поддерживают плагины. Например, у Jenkins есть более 1500 плагинов для интеграции со сторонними платформами, для расширения пользовательского интерфейса, администрирования, управления исходным кодом и сборкой.

При использовании CI/CD-инструмента разработчики должны убедиться, что все параметры сконфигурированы вне приложения через переменные окружения. CI/CD-инструменты позволяют устанавливать значения этих переменных, маскировать пароли и ключи учетных записей, а также настраивать их во время развертывания для конкретного окружения.
Также в CD-инструментах присутствуют дашборды и отчетность. В случае сбоя сборки или поставки они оповещают об этом. При интеграции CD с системой контроля версий и agile-инструментами облегчается поиск изменений кода и пользовательских историй, вошедших в сборку.

Реализация CI/CD-конвейеров с Kubernetes и бессерверными архитектурами


Многие команды, использующие CI/CD-конвейеры в облаках используют контейнеры, такие как Docker, и системы оркестрации, такие как Kubernetes. Контейнеры позволяют стандартизировать упаковку, поставку и упростить масштабирование и уничтожение окружений с непостоянной нагрузкой.

Есть множество вариантов совместного использования контейнеров, инфраструктуры как код и CI/CD-конвейеров. Подробнее изучить это вы можете в статьях Kubernetes with Jenkins и Kubernetes with Azure DevOps.

Архитектура бессерверных вычислений представляет собой еще один способ развертывания и масштабирования приложений. В бессерверном окружении инфраструктурой полностью управляет поставщик облачных услуг, а приложение потребляет ресурсы по мере необходимости в соответствии с его настройками. Например, в AWS бессерверные приложения запускаются через функции AWS Lambda, развертывание которых может быть интегрировано в CI/CD-конвейер Jenkins с помощью плагина.

CI/CD обеспечивает более частое развертывание кода


Итак, подведем итоги. CI упаковывает, тестирует сборки и оповещает разработчиков, если что-то пошло не так. CD автоматически разворачивает приложения и выполняет дополнительные тесты.

CI/CD-конвейеры предназначены для организаций, которым необходимо часто вносить изменения в приложения с надежным процессом поставки. Помимо стандартизации сборки, разработки тестов и автоматизации развертываний мы получаем целостный производственный процесс по развертыванию изменений кода. Внедрение CI/CD позволяет разработчикам сосредоточиться на улучшении приложений и не тратить силы на его развертывание.

CI/CD является одной из DevOps-практик, поскольку направлена на борьбу с противоречиями между разработчиками, которые хотят часто вносить изменения, и эксплуатацией, требующей стабильности. Благодаря автоматизации, разработчики могут вносить изменения чаще, а команды эксплуатации, в свою очередь, получают большую стабильность, поскольку конфигурация окружений стандартизирована и в процессе поставки осуществляется непрерывное тестирование. Также настройка переменных окружения отделена от приложения и присутствуют автоматизированные процедуры отката.

Эффект от внедрения CI/CD-конвейеров можно измерить в виде ключевых показателей эффективности (KPI) DevOps. Такие KPI как частота поставки (deployment frequency), время реализации изменений (change lead time) и среднее время восстановления после инцидента (mean time to recovery) часто улучшаются при внедрении CI/CD с непрерывным тестированием. Однако CI/CD это лишь один из процессов, который может способствовать этим улучшениям. Есть и другие условия для увеличения частоты поставки.

Для начала работы с CI/CD команде разработчиков и эксплуатации необходимо совместно определиться с технологиями, практиками и приоритетами. Команды должны выработать консенсус в отношении правильных подходов к своему бизнесу и технологиям, чтобы после внедрения CI/CD команда постоянно придерживалась выбранных практик.



Краткий обзор инструментов CICD: Gitlab CI, Docker, Ansible


Подробнее..

Перевод Знакомство с Docker

01.06.2021 08:12:59 | Автор: admin

Это первая статья в цикле Знакомство с Docker. Если вы раньше не работали с Docker, мы расскажем, что он из себя представляет.

Что такое Docker?

Docker - это инструмент DevOps для контейнеризации сервисов и процессов... Подождите... Подождите... Подождите! Что такое DevOps? Что такое контейнеризация? Какие услуги и процессы я могу контейнеризовать? Начнём с самого начала.

DevOps можно понимать как концепцию, объединяющую группы разработчиков и администраторов. Проще говоря, разработчики - это люди, которые пишут код, создают приложение, а администраторы - это инженеры, которые отвечают за доставку приложения, распределения ресурсов для него, резервного копирования данных, проверки качества, мониторинга и т. д. Таким образом, DevOps инженер - специалист, который создаёт мост между ними.

Контейнер - это не более чем процесс, который выполняется изолированно в операционной системе. У него есть собственная сеть, собственная файловая система и выделенная память. Вы можете подумать, а почему бы просто не использовать виртуальную машину? Что ж, виртуальная машина - это отдельная ОС, сильно загруженная множеством других процессов, которые могут вам никогда не понадобиться, вместо виртуализации всей операционной системы для запуска одной службы вы можете виртуализировать службу. Точнее говоря, вы можете создать легкую виртуальную среду для одной службы. Этими службами могут быть серверы Nginx, NodeJS или приложения angular. И Docker помогает нам в этом.

Название Docker происходит от слова док (dock). Док используется для погрузки и разгрузки грузов на кораблях. Здесь можно провести простую аналогию, груз может быть контейнерами, а корабль может быть нашей операционной системой. Все товары в составе груза изолированы от товаров другого груза и самого корабля. Точно так же в Docker процесс одного Docker контейнера (Docker Container) изолирован от процесса другого контейнера и самой операционной системы.

Как работает контейнеризация

Docker использует технологию Linux Containers (LXC) и механизмы ядра Linux. Поскольку у docker-контейнера нет собственной операционной системы, он полагается на хостовую операционную систему. Контейнер, созданный в Linux, может быть запущен в любом дистрибутиве Linux, но не может работать в Windows, и то же самое касается образа, созданного в Windows. Docker расширяет возможности LXC, но также использует контрольные группы (cgroups), которые позволяют ядру хоста разделять использование ресурсов (ЦП, память, дисковый ввод-вывод, сеть и т. д.) на уровни изоляции, называемые пространствами имён (namespaces).

Как создать Docker контейнер?

Чтобы создать Docker контейнер, нам нужно сначала создать архив, содержащий все файлы и зависимости, необходимые для нашего проекта. Этот архив называется Docker образом (Docker Image). Важно помнить, что после создания Docker образа его уже нельзя изменить или модифицировать.

Большое количество готовых образов можно найти в DockerHub, общедоступном репозитории Docker, который позволяет вам делиться своими образами или использовать образы, созданные другими людьми. Вы также можете создавать свои собственные образы и помещать их в свой частный репозиторий (например, Harbor). В дальнейшем этот образ будет использован для создания контейнеров. Один и тот же образ можно использовать для создания одного или нескольких контейнеров, используя Docker-CLI. А что такое Docker CLI спросите вы?

Рассмотрим архитектуру Docker,

  1. Docker демонслушает запросы Docker API и управляет всеми объектами Docker, такими как образы, контейнеры, сети и тома. Это основная служба Docker, которая необходима для работы контейнеров и других компонентов Docker. Если Docker демон перестанет работать, так же перестанут работать все запущенные контейнеры.

  2. Docker демон также предоставляет REST API. Различные инструменты могут использовать его для взаимодействия с демоном. Вы также можете создать приложение, для работы с Docker REST API.

  3. Docker-CLIэто инструмент командной строки, который позволяет вам общаться с демоном Docker черезREST API.

Сеть Docker

Docker предусматривает несколько режимов работы сети. Подробнее о работе сети можно прочитать в нашей статье Сеть контейнеров это не сложно.

  • Host networks -Контейнер Docker будет использовать сеть хоста, соответственно он не будет изолирован с точки зрения сети, это не коснётся изоляции контейнера в целом, например изоляции процессов и файловой системы.

  • Bridge networks - Позволяет изолировать ваши приложения, но они могут взаимодействовать между собой и принимать трафик снаружи, если включено сопоставления портов (port forwarding).

  • Overlay networks - Оверлейные сети соединяют вместе несколько демонов Docker и позволяют службам Docker Swarm взаимодействовать друг с другом. Docker Swarm (аналог Kubernetes) может использоваться, если у вас несколько серверов с Docker.

  • Macvlan networks - Позволяет назначить MAC-адрес контейнеру, чтобы он отображался как физическое устройство в вашей сети.

  • None -Сеть отсутствует, соответственно вы не сможете подключиться к контейнеру.

И всё же, почему стоит использовать Docker?

  • Как разработчик вы можете легко упаковать свой проект со всеми его зависимостями и файлами, создать для него образ, и при этом быть уверенными, что он будет работать в любом дистрибутиве Linux.

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

  • Вы можете ограничить потребляемые контейнером ресурсы - ЦП и память, это позволит запустить больше контейнеров на одном сервере.

  • Возможность запуска нескольких контейнеров из одного образа, позволит сэкономить место на диске и в репозитории образов.

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

  • Вы можете передать ваш образ коллегам из команды тестирования, они смогут создать несколько экземпляров приложения (контейнеров) из этого образа и выполнять необходимые тесты.

Вместо заключения

Это только первая статья из цикла знакомство с Docker. В следующих статьях мы расскажем о работе с командной строкой Docker и создании собственных образов.

Подробнее..

OKD4 общедоступный релиз уже здесь

20.07.2020 22:15:29 | Автор: admin
Рабочая группа OKD рада сообщить о выходе общедоступного релиза системы OKD4, которая представляет собой community-версию Red Hat OpenShift Kubernetes.



Red Hat в очередной раз подтверждает приверженность принципам open source и открытого сотрудничества с сообществами разработки Kubernetes и других облачно-ориентированных инициатив.

Истоки OKD


Когда в апреле 2012 года Red Hat впервые запустила Origin как опенсорсный upstream-вариант OpenShift, было сложно представить, насколько быстрым и успешным будет развитие облачно-ориентированных технологий. Последующие годы запомнились взлетом контейнеров, созданием OCI и Fedora CoreOS, а также недавним переездом Operator Framework под крышу CNCF. Без этих инновационных технологий и сообществ, в которых они были созданы, появление OKD4 было бы невозможно.

Во время релиза третьей версии OKD выступал в качестве стабильной основы для OpenShift Container Platform, играя роль upstream-дистрибутива на основе community-компонентов, таких как CentOS, Project Atomic и других. С появлением Universal Base Image взаимоотношения между OKD и OCP изменились: на смену формату upstream-downstream пришло то, что мы называем родственные дистрибутивы (sibling distributions). Образы теперь строятся на базе RHEL7 и могут распространяться одновременно и для OKD, и для OCP без какой-либо пересборки. В результате это позволяет обоим дистрибутивам получать обновления, включая исправления безопасности RHEL7, а также обеспечивает стабильный базис для Red Hat Enterprise Linux.



В OpenShift 4.x особое внимание уделяется высокой доступности, наблюдаемости и бесшовном обновлении. С выходом OKD 4 сообщество не только получает автоматический доступ к этим функциям, но и возможность влиять на развитие платформы (через репозиторий процесс улучшений), а также пространство для экспериментов, дискуссий и обмена знаниями. Широко используемый в OKD 4 шаблон Operators позволяет пользователям эффективно сопровождать кластеры на протяжении всего срока службы.

Особенности релиза


OKD4 использует в качестве базовой ОС для своих узлов Fedora CoreOS, предоставляя кластер с последними исправлениями безопасности, новыми функциями (вроде cgroups v2) и обновленным ПО. OKD4 использует те же образы, что и соответствующая версия OpenShift Container Platform. Поэтому сообщество может полноценно участвовать в разработке системы и модифицировать любые части кластера для достижения тех или иных целей.

При этом кластер сохраняет знакомые по OKD3 особенности: его можно устанавливать в user environment, конфигурировать по своему вкусу и обновлять.

В чем отличия OKD от OCP


У OKD4 есть ряд важных отличий от OCP:

Во-первых, как community-дистрибутиву ему не нужен pull-секрет с сайта https://openshift.com/try. Все образы OKD4 доступны без дополнительной аутентификации. Базовый образ ОС для OKD4 загружается с сайта https://getfedora.org/en/coreos/download/. Однако для некоторых опциональных операторов с сайта operatorhub.io pull-секрет все же требуется, поэтому по умолчанию OKD4 устанавливает исходник только с community-операторами, подробнее см. FAQ.

Во-вторых, OCP это особый дистрибутив Kubernetes, с упором на высокую доступность и продакшн-нагрузки. Отсюда и ограничения на конфигурацию кластеров например, не поддерживаются конфигурации single master. В свою очередь, OKD4 легко позволяет создавать такие конфигурации для тех же девелоперских или тестовых stage-сред. Хотя такие кластеры и нельзя потом обновить до следующей версии.

Новые nightly-релизы OKD4 создаются после того, как OCP проходит тестирование в рамках нашей системы CI. Каждые две недели мы будем перемещать nightly-релиз в канал stable, чтобы пользователи могли получать обновления к новейшему и оттестированному коду без переключения каналов.

Как приступить к работе с OKD4


OKD4 устанавливается так же легко, как и OCP4, см. инструкции в руководстве Getting Started.

Документация по OKD доступна на сайте docs.okd.io

Сообщать о неполадках можно на OKD Github Repo по адресу https://github.com/openshift/okd

Техническая поддержка осуществляется здесь: #openshift-users channel on Kubernetes Slack

Уже пользуетесь OKD?


В этом случае потратьте, пожалуйста, пять минут на заполнение опросника OKD Adoption, чтобы помочь рабочей группа OKD планировать дальнейшее развитие проекта и лучше понять характер рабочих нагрузок, для которых он применяется!

Включайтесь в работу


На сайте сообщества OKD.io можно загрузить последний релиз, ознакомиться с ключевыми upstream-проектами, над которыми мы работаем, лучше узнать наших конечных пользователей и рабочие нагрузки, для которых используется OKD, а также найти ссылки на последние информационные ресурсы.

Рабочая группа OKD собирается дважды в неделю, чтобы обсудить текущее состояние и последующие шаги разработки. Время и место встреч отслеживаются в репо openshift/community.

Повестку и детали предстоящих встреч можно найти здесь: https://github.com/openshift/community/projects/1

Русскоязычное сообщество OpenShift в Telegram:
https://t.me/ru_openshift

Вступайте в наши ряды


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

Подробнее..

14 лучших практик разработки приложений на OpenShift

18.02.2021 14:23:54 | Автор: admin

Много работая с командами разработки, только что перешедшими на OpenShift, мы стремимся дать им рекомендации и лучшие практики для успешного создания и внедрения приложений на этой платформе. По итогам этой работы мы отобрали 14 ключевых, на наш взгляд, практик, которые можно разбить на две категории: надежность приложений и безопасность приложений. Эти категории пересекаются, поскольку чем выше надежность, тем лучше безопасность, и наоборот, а сам список лучших практик выглядит следующим образом.

Надежность приложений

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

1. Не храните конфигурацию приложения внутри контейнера

Если контейнерный образ содержит конфигурацию для какой-то конкретной среды (Dev, QA, Prod), его не получится без изменений переносить между средами. Это плохо с точки зрения надежности процесса выпуска версий, поскольку в продакшн пойдет уже не тот образ, который тестировался на предыдущих этапах. Поэтому не держите внутри контейнера конфигурацию приложения для конкретной среды, а храните ее отдельно, например, с помощью ConfigMaps и Secrets.

2. Задавайте ресурсные требования и лимиты в определениях podа

Без должной настройки требований к ресурсам приложения могут создавать непосильную нагрузку на память и процессор. И наоборот, имея явно прописанные требования приложения к ЦП и памяти, кластер может эффективно выполнять диспетчеризацию так, чтобы предоставлять приложению запрашиваемые ресурсы.

3. Прописывайте зонды активности (liveness) и готовности (readiness) в определениях podа

С помощью этих зондов кластер может обеспечивать базовую устойчивость: перезапускать приложение, если не проходит liveness, или больше не маршрутизировать на него трафик, когда не отвечает readiness. Подробнее см. раздел Мониторинг работоспособности приложений в документации OpenShift Platform.

4. Используйте PodDisruptionBudget для защиты приложений

Иногда podы приходится убирать с узла кластера, например, при обслуживании хоста, или когда autoscaler даунсайзит кластер, отключая лишние узлы. Чтобы приложение при этом оставалось доступным, надо настроить объекты PodDistruptionBudget.

5. Правильное завершение работы podов

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

6. Один контейнер один процесс

Старайтесь, чтобы каждый процесс работал в своем собственном контейнере. Это повышает изоляцию процессов и предотвращает проблемы с маршрутизацией сигналов и появление зомби-процессов, которые иначе придется периодически вычищать. Подробнее см. разделИзбегайте нескольких процессовв документации OpenShift Platform.

7. Используйте системы мониторинга приложений и оповещения

Мониторинг приложений средствами Prometheus и Grafana помогает поддерживать нормальную работу приложений в продакшн-режиме согласно требованиям бизнеса.

8. Пусть приложения пишут свои логи в stdout/stderr

Тогда OpenShift сможет собирать и пересылать их в централизованную систему обработки (ELK, Splunk). Логи это бесценный ресурс при анализе работы приложения в продакшн-режиме. Кроме того, оповещения, генерируемые на базе содержимого логов, помогают проконтролировать, что приложение работает как задумано.

9. Изучите целесообразность применения Circuit breakers, Timeouts, Retries, Rate Limiting

Эти механизмы повышают устойчивость приложения к отказам, защищая от перегрузок (Rate Limiting, Circuit Breakers) и помогая справляться с сетевыми проблемами (Timeouts, Retries). Рассмотрите возможность применения решения OpenShift Service Mesh, которое позволяет реализовать эти функции, не трогая код приложений.

Безопасность приложений

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

10. Используйте только доверенные контейнерные образы

Применяйте вендор-образы везде, где это возможно, поскольку они гарантировано тестируются, дорабатываются на безопасность и обеспечиваются поддержкой. Что касается community-образов, используйте наработки только тех сообществ, которым доверяете. И помните, что в публичных реестрах, вроде Docker Hub, имеются образы неизвестного происхождения не используйте их ни в коем случае!

11. Используйте последние версии базовых контейнерных образов

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

12. build-образы отдельно, runtime-образы отдельно

Build-образ содержит зависимости, которые нужны при сборке приложения, но не нужны при запуске. Поэтому создавайте отдельные runtime-образы с минимумом зависимостей, чтобы уменьшить поверхность атак, а заодно и размер образа.

13. Restricted security context constraint (SCC) везде, где только возможно

Модифицируйте образы, чтобы они могли работать в рамках restricted SCC (подробнее см. раздел Поддержка произвольных идентификаторов пользователей в документации). Риски взлома приложений включают в себя и ситуации, когда злоумышленник получает контроль над самим приложением, и restricted SCC позволяет обезопасить узел кластера на этот случай.

14. TLS для защиты коммуникаций между компонентами приложения

Компоненты приложения могут пересылать друг другу конфиденциальные данные. Если сеть, в которой работает OpenShift, не может считаться безопасной, то трафик между компонентами приложения можно защитить с помощью TLS-шифрования, а уже упомянутый OpenShift Service Mesh позволяет сделать это, не трогая код приложений.

Заключение

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

Подробнее..

Перевод Сеть контейнеров это не сложно

26.05.2021 22:23:37 | Автор: admin

Работа с контейнерами многим кажется волшебством, пришло время разобраться как работает сеть контейнеров. Мы покажем на примерах, что это совсем не сложно. Помните, что контейнеры - всего лишь изолированные процессы Linux.

В этой статье мы ответим на следующие вопросы:

  • Как виртуализировать сетевые ресурсы, чтобы контейнеры думали, что у каждого из них есть выделенный сетевой стек?

  • Как превратить контейнеры в дружелюбных соседей, не дать им мешать друг другу и научить хорошо общаться?

  • Как настроить сетевой доступ из контейнера во внешний мир (например, в Интернет)?

  • Как получить доступ к контейнерам, работающим на сервере, из внешнего мира (публикация портов)?

Отвечая на эти вопросы, мы настроим сеть контейнеров с нуля, используя стандартные инструменты Linux. В результате станет очевидно, что сеть контейнеров - это не что иное, как простая комбинация хорошо известных возможностей Linux:

  • Network namespaces

  • Virtual Ethernet devices (veth)

  • Virtual network switches (bridge)

  • IP маршрутизация и преобразование сетевых адресов (NAT)

Нам потребуется немного сетевой магии и никакого кода ...

С чего начать?

Все примеры в статье были сделаны на виртуальной машине CentOS 8. Но вы можете выбрать тот дистрибутив, который вам нравится.

Создадим виртуальную машину с помощью Vagrant и подключимся к ней по SSH:

$ vagrant init centos/8$ vagrant up$ vagrant ssh[vagrant@localhost ~]$ uname -aLinux localhost.localdomain 4.18.0-147.3.1.el8_1.x86_64

Мы не будем использовать какое-либо популярное решение для контейнеризации (например, docker или podman). Вместо этого мы сосредоточимся на основных концепциях и воспользуемся минимальным набором инструментов для достижения наших учебных целей.

Изоляция контейнеров с помощью Network namespaces

Что составляет сетевой стек Linux? Ну, очевидно, набор сетевых устройств. Что еще? Набор правил маршрутизации. И не забываем про настройку netfilter, создадим необходимые правила iptables.

Напишем небольшой скрипт inspect-net-stack.sh:

#!/usr/bin/env bashecho "> Network devices"ip linkecho -e "\n> Route table"ip routeecho -e "\n> Iptables rules"iptables --list-rules

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

$ sudo iptables -N ROOT_NS

Запускаем скрипт:

$ sudo ./inspect-net-stack.sh> Network devices1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000    link/ether 52:54:00:e3:27:77 brd ff:ff:ff:ff:ff:ff> Route tabledefault via 10.0.2.2 dev eth0 proto dhcp metric 10010.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100> Iptables rules-P INPUT ACCEPT-P FORWARD ACCEPT-P OUTPUT ACCEPT-N ROOT_NS

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

Мы уже упоминали об одном из Linux namespaces, используемых для изоляции контейнеров, которое называет сетевое пространство имён (Network namespace). Если заглянуть в man ip-netns, то мы прочтём, что Network namespace логически является копией сетевого стека со своими собственными маршрутами, правилами брандмауэра и сетевыми устройствами. Мы не будем затрагивать другие Linux namespaces в этой статье и ограничимся только областью видимости сетевого стека.

Для создания Network namespace нам достаточно утилиты ip, которая входим в популярный пакет iproute2. Создадим новое сетевое пространство имён:

$ sudo ip netns add netns0$ ip netnsnetns0

Новое сетевое пространство имён создано, но как начать его использовать? Воспользуемся командой Linux под названием nsenter. Она осуществляет вход в одно или несколько указанных пространств имен, а затем выполняет в нём указанную программу:

$ sudo nsenter --net=/var/run/netns/netns0 bash# The newly created bash process lives in netns0$ sudo ./inspect-net-stack.sh> Network devices1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00> Route table> Iptables rules-P INPUT ACCEPT-P FORWARD ACCEPT-P OUTPUT ACCEPT

Приведённый выше пример показывает, что процесс bash, работающий внутри пространства имён netns0, видит совершенно другой сетевой стек. Отсутствуют правила маршрутизации, и правила iptables, есть только один loopback interface. Все идет по плану...

Подключаем контейнер к хосту через virtual Ethernet devices (veth)

Выделенный сетевой стек будет бесполезен, если к нему отсутствует доступ. К счастью, Linux предоставляет подходящее средство для этого - virtual Ethernet devices (veth)! Согласно man veth, veth-device - это виртуальные устройства Ethernet. Они работают как туннели между сетевыми пространствами имён для создания моста к физическому сетевому устройству в другом пространстве имён, а также могут использоваться как автономные сетевые устройства.

Виртуальные Ethernet устройства всегда работают парами. Создадим их прямо сейчас:

$ sudo ip link add veth0 type veth peer name ceth0

С помощью этой единственной команды мы только что создали пару взаимосвязанных виртуальных Ethernet устройств. Имена veth0 и ceth0 были выбраны произвольно:

$ ip link1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000    link/ether 52:54:00:e3:27:77 brd ff:ff:ff:ff:ff:ff5: ceth0@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/ether 66:2d:24:e3:49:3f brd ff:ff:ff:ff:ff:ff6: veth0@ceth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/ether 96:e8:de:1d:22:e0 brd ff:ff:ff:ff:ff:ff

И veth0, и ceth0 после создания находятся в сетевом стеке хоста (также называемом Root Network namespace). Чтобы связать корневое пространство имён с пространством имён netns0, нам нужно сохранить одно из устройств в корневом пространстве имён и переместить другое в netns0:

$ sudo ip link set ceth0 netns netns0# List all the devices to make sure one of them disappeared from the root stack$ ip link1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000    link/ether 52:54:00:e3:27:77 brd ff:ff:ff:ff:ff:ff6: veth0@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/ether 96:e8:de:1d:22:e0 brd ff:ff:ff:ff:ff:ff link-netns netns0

Как только мы включаем устройства и назначаем правильные IP-адреса, любой пакет, происходящий на одном из них, немедленно появляется на его одноранговом устройстве, соединяющем два пространства имён. Начнем с корневого пространства имён:

$ sudo ip link set veth0 up$ sudo ip addr add 172.18.0.11/16 dev veth0

Продолжим сnetns0:

$ sudo nsenter --net=/var/run/netns/netns0$ ip link set lo up  # whoops$ ip link set ceth0 up$ ip addr add 172.18.0.10/16 dev ceth0$ ip link1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:005: ceth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000    link/ether 66:2d:24:e3:49:3f brd ff:ff:ff:ff:ff:ff link-netnsid 0

Проверяем подключение:

# From netns0, ping root's veth0$ ping -c 2 172.18.0.11PING 172.18.0.11 (172.18.0.11) 56(84) bytes of data.64 bytes from 172.18.0.11: icmp_seq=1 ttl=64 time=0.038 ms64 bytes from 172.18.0.11: icmp_seq=2 ttl=64 time=0.040 ms--- 172.18.0.11 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 58msrtt min/avg/max/mdev = 0.038/0.039/0.040/0.001 ms# Leave netns0$ exit# From root namespace, ping ceth0$ ping -c 2 172.18.0.10PING 172.18.0.10 (172.18.0.10) 56(84) bytes of data.64 bytes from 172.18.0.10: icmp_seq=1 ttl=64 time=0.073 ms64 bytes from 172.18.0.10: icmp_seq=2 ttl=64 time=0.046 ms--- 172.18.0.10 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 3msrtt min/avg/max/mdev = 0.046/0.059/0.073/0.015 ms

Обратите внимание, если мы попытаемся проверить доступность любых других адресов из пространства имен netns0, у нас ничего не получится:

# Inside root namespace$ ip addr show dev eth02: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000    link/ether 52:54:00:e3:27:77 brd ff:ff:ff:ff:ff:ff    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic noprefixroute eth0       valid_lft 84057sec preferred_lft 84057sec    inet6 fe80::5054:ff:fee3:2777/64 scope link       valid_lft forever preferred_lft forever# Remember this 10.0.2.15$ sudo nsenter --net=/var/run/netns/netns0# Try host's eth0$ ping 10.0.2.15connect: Network is unreachable# Try something from the Internet$ ping 8.8.8.8connect: Network is unreachable

Для таких пакетов в таблице маршрутизации netns0 просто нет маршрута. В настоящий момент существует единственный маршрут до сети 172.18.0.0/16:

# From netns0 namespace:$ ip route172.18.0.0/16 dev ceth0 proto kernel scope link src 172.18.0.10

В Linux есть несколько способов заполнения таблицы маршрутизации. Один из них - извлечение маршрутов из подключенных напрямую сетевых интерфейсов. Помните, что таблица маршрутизации в netns0 была пустой сразу после создания пространства имен. Но затем мы добавили туда устройство ceth0 и присвоили ему IP-адрес 172.18.0.10/16. Поскольку мы использовали не простой IP-адрес, а комбинацию адреса и сетевой маски, сетевому стеку удалось извлечь из него информацию о маршрутизации. Каждый пакет, предназначенный для сети 172.18.0.0/16, будет отправлен через устройство ceth0. Но все остальные пакеты будут отброшены. Точно так же есть новый маршрут в корневом пространстве имен:

# From root namespace:$ ip route# ... omitted lines ...172.18.0.0/16 dev veth0 proto kernel scope link src 172.18.0.11

На этом этапе мы ответили на первый вопрос. Теперь мы знаем, как изолировать, виртуализировать и подключать сетевые стеки Linux.

Объединение контейнеров с помощью virtual network switch (bridge)

Вся идея контейнеризации сводится к эффективному совместному использованию ресурсов. То есть мы крайне редко запускаем на хосте единственный контейнер. Вместо этого стараемся запустить как можно больше изолированных процессов на одном хосте. Итак, чтобы произошло, если бы мы разместили несколько контейнеров на одном хосте, следуя описанному выше подходу? Добавим второй контейнер:

# From root namespace$ sudo ip netns add netns1$ sudo ip link add veth1 type veth peer name ceth1$ sudo ip link set ceth1 netns netns1$ sudo ip link set veth1 up$ sudo ip addr add 172.18.0.21/16 dev veth1$ sudo nsenter --net=/var/run/netns/netns1$ ip link set lo up$ ip link set ceth1 up$ ip addr add 172.18.0.20/16 dev ceth1

Проверим доступность:

# From netns1 we cannot reach the root namespace!$ ping -c 2 172.18.0.21PING 172.18.0.21 (172.18.0.21) 56(84) bytes of data.From 172.18.0.20 icmp_seq=1 Destination Host UnreachableFrom 172.18.0.20 icmp_seq=2 Destination Host Unreachable--- 172.18.0.21 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 55mspipe 2# But there is a route!$ ip route172.18.0.0/16 dev ceth1 proto kernel scope link src 172.18.0.20# Leaving netns1$ exit# From root namespace we cannot reach the netns1$ ping -c 2 172.18.0.20PING 172.18.0.20 (172.18.0.20) 56(84) bytes of data.From 172.18.0.11 icmp_seq=1 Destination Host UnreachableFrom 172.18.0.11 icmp_seq=2 Destination Host Unreachable--- 172.18.0.20 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 23mspipe 2# From netns0 we CAN reach veth1$ sudo nsenter --net=/var/run/netns/netns0$ ping -c 2 172.18.0.21PING 172.18.0.21 (172.18.0.21) 56(84) bytes of data.64 bytes from 172.18.0.21: icmp_seq=1 ttl=64 time=0.037 ms64 bytes from 172.18.0.21: icmp_seq=2 ttl=64 time=0.046 ms--- 172.18.0.21 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 33msrtt min/avg/max/mdev = 0.037/0.041/0.046/0.007 ms# But we still cannot reach netns1$ ping -c 2 172.18.0.20PING 172.18.0.20 (172.18.0.20) 56(84) bytes of data.From 172.18.0.10 icmp_seq=1 Destination Host UnreachableFrom 172.18.0.10 icmp_seq=2 Destination Host Unreachable--- 172.18.0.20 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 63mspipe 2

Что-то пошло не так... По какой-то причине мы не можем подключиться из netns1 к root namespace. А из root namespace мы не можем подключиться к netns1. Однако, поскольку оба контейнера находятся в одной IP-сети 172.18.0.0/16, есть доступ к veth1 хоста из контейнера netns0. Интересно...

Возможно, мы столкнулись с конфликтом маршрутов. Давайте проверим таблицу маршрутизации в root namespace:

$ ip route# ... omitted lines ...172.18.0.0/16 dev veth0 proto kernel scope link src 172.18.0.11172.18.0.0/16 dev veth1 proto kernel scope link src 172.18.0.21

После добавления второй пары veth в таблице маршрутизации root namespace появился новый маршрут 172.18.0.0/16 dev veth1 proto kernel scope link src 172.18.0.21, но маршрут до этой подсети уже существовал! Когда второй контейнер пытается проверить связь с устройством veth1, используется первый маршрут и мы видим ошибку подключения. Если бы мы удалили первый маршрут sudo ip route delete 172.18.0.0/16 dev veth0 proto kernel scope link src 172.18.0.11 и перепроверили подключение, то увидели бы обратную ситуацию, то есть подключение netns1 будет восстановлено, но netns0 останется в подвешенном состоянии.

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

Рассмотрим Linux Bridge - еще один виртуализированный сетевой объект! Linux Bridge ведёт себя как коммутатор. Он пересылает пакеты между подключенными к нему интерфейсами. А поскольку это коммутатор, то он работает на уровне L2 (то есть Ethernet).

Чтобы предыдущие этапы нашего эксперимента в дальнейшем не вносили путаницы, удалим существующие сетевые пространства имён:

$ sudo ip netns delete netns0$ sudo ip netns delete netns1# But if you still have some leftovers...$ sudo ip link delete veth0$ sudo ip link delete ceth0$ sudo ip link delete veth1$ sudo ip link delete ceth1

Заново создаём два контейнера. Обратите внимание, мы не назначаем IP-адреса новым устройствам veth0 и veth1:

$ sudo ip netns add netns0$ sudo ip link add veth0 type veth peer name ceth0$ sudo ip link set veth0 up$ sudo ip link set ceth0 netns netns0$ sudo nsenter --net=/var/run/netns/netns0$ ip link set lo up$ ip link set ceth0 up$ ip addr add 172.18.0.10/16 dev ceth0$ exit$ sudo ip netns add netns1$ sudo ip link add veth1 type veth peer name ceth1$ sudo ip link set veth1 up$ sudo ip link set ceth1 netns netns1$ sudo nsenter --net=/var/run/netns/netns1$ ip link set lo up$ ip link set ceth1 up$ ip addr add 172.18.0.20/16 dev ceth1$ exit

Убедимся, что на хосте нет новых маршрутов:

$ ip routedefault via 10.0.2.2 dev eth0 proto dhcp metric 10010.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100

И, наконец, создадим bridge интерфейс:

$ sudo ip link add br0 type bridge$ sudo ip link set br0 up

Теперь подключим к нему veth0 и veth1:

$ sudo ip link set veth0 master br0$ sudo ip link set veth1 master br0

... и проверим возможность подключения между контейнерами:

$ sudo nsenter --net=/var/run/netns/netns0$ ping -c 2 172.18.0.20PING 172.18.0.20 (172.18.0.20) 56(84) bytes of data.64 bytes from 172.18.0.20: icmp_seq=1 ttl=64 time=0.259 ms64 bytes from 172.18.0.20: icmp_seq=2 ttl=64 time=0.051 ms--- 172.18.0.20 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 2msrtt min/avg/max/mdev = 0.051/0.155/0.259/0.104 ms
$ sudo nsenter --net=/var/run/netns/netns1$ ping -c 2 172.18.0.10PING 172.18.0.10 (172.18.0.10) 56(84) bytes of data.64 bytes from 172.18.0.10: icmp_seq=1 ttl=64 time=0.037 ms64 bytes from 172.18.0.10: icmp_seq=2 ttl=64 time=0.089 ms--- 172.18.0.10 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 36msrtt min/avg/max/mdev = 0.037/0.063/0.089/0.026 ms

Прекрасно! Все отлично работает. При этом мы даже не настраивали интерфейсы veth0 и veth1. Мы назначили только два IP-адреса интерфейсам ceth0 и ceth1. Но поскольку они оба находятся в одном сегменте Ethernet (подключены к виртуальному коммутатору), существует возможность подключения на уровне L2:

$ sudo nsenter --net=/var/run/netns/netns0$ ip neigh172.18.0.20 dev ceth0 lladdr 6e:9c:ae:02:60:de STALE$ exit$ sudo nsenter --net=/var/run/netns/netns1$ ip neigh172.18.0.10 dev ceth1 lladdr 66:f3:8c:75:09:29 STALE$ exit

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

Настраиваем сетевой доступ из контейнера во внешний мир (IP routing and masquerading)

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

$ sudo nsenter --net=/var/run/netns/netns0$ ping 10.0.2.15  # eth0 addressconnect: Network is unreachable

Интерфейс eth0 не доступен. Всё очевидно, в netns0 отсутствует маршрут для этого подключения:

$ ip route172.18.0.0/16 dev ceth0 proto kernel scope link src 172.18.0.10

Корневое пространство имён также не может взаимодействовать с контейнерами:

# Use exit to leave netns0 first:$ ping -c 2 172.18.0.10PING 172.18.0.10 (172.18.0.10) 56(84) bytes of data.From 213.51.1.123 icmp_seq=1 Destination Net UnreachableFrom 213.51.1.123 icmp_seq=2 Destination Net Unreachable--- 172.18.0.10 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 3ms$ ping -c 2 172.18.0.20PING 172.18.0.20 (172.18.0.20) 56(84) bytes of data.From 213.51.1.123 icmp_seq=1 Destination Net UnreachableFrom 213.51.1.123 icmp_seq=2 Destination Net Unreachable--- 172.18.0.20 ping statistics ---2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 3ms

Чтобы установить связь между корневым пространством имён и пространством имён контейнера, нам нужно назначить IP-адрес сетевому интерфейсу моста:

$ sudo ip addr add 172.18.0.1/16 dev br0

Теперь после того, как мы назначили IP-адрес интерфейсу моста, мы получили маршрут в таблице маршрутизации хоста:

$ ip route# ... omitted lines ...172.18.0.0/16 dev br0 proto kernel scope link src 172.18.0.1$ ping -c 2 172.18.0.10PING 172.18.0.10 (172.18.0.10) 56(84) bytes of data.64 bytes from 172.18.0.10: icmp_seq=1 ttl=64 time=0.036 ms64 bytes from 172.18.0.10: icmp_seq=2 ttl=64 time=0.049 ms--- 172.18.0.10 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 11msrtt min/avg/max/mdev = 0.036/0.042/0.049/0.009 ms$ ping -c 2 172.18.0.20PING 172.18.0.20 (172.18.0.20) 56(84) bytes of data.64 bytes from 172.18.0.20: icmp_seq=1 ttl=64 time=0.059 ms64 bytes from 172.18.0.20: icmp_seq=2 ttl=64 time=0.056 ms--- 172.18.0.20 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 4msrtt min/avg/max/mdev = 0.056/0.057/0.059/0.007 ms

Контейнер, вероятно, также получил возможность пинговать интерфейс моста, но они все ещё не могут связаться с хостом eth0. Нам нужно добавить маршрут по умолчанию для контейнеров:

$ sudo nsenter --net=/var/run/netns/netns0$ ip route add default via 172.18.0.1$ ping -c 2 10.0.2.15PING 10.0.2.15 (10.0.2.15) 56(84) bytes of data.64 bytes from 10.0.2.15: icmp_seq=1 ttl=64 time=0.036 ms64 bytes from 10.0.2.15: icmp_seq=2 ttl=64 time=0.053 ms--- 10.0.2.15 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 14msrtt min/avg/max/mdev = 0.036/0.044/0.053/0.010 ms# And repeat the change for netns1

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

Отлично, нам удалось добиться сетевой связности контейнеров с корневым пространством имён. Теперь давайте попробуем подключить их к внешнему миру. По умолчанию переадресация пакетов (ip packet forwarding), то есть функциональность маршрутизатора в Linux отключена. Нам нужно её включить

# In the root namespacesudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'

Теперь самое интересное - проверка подключения:

$ sudo nsenter --net=/var/run/netns/netns0$ ping 8.8.8.8# hangs indefinitely long for me...

Всё равно не работает. Мы что-то упустили? Если бы контейнер отправлял пакеты во внешний мир, сервер-получатель не смог бы отправлять пакеты обратно в контейнер, потому что IP-адрес контейнера является частным и правила маршрутизации для этого конкретного IP-адреса известны только в локальной сети. К тому же многие контейнеры в мире имеют один и тот же частный IP-адрес 172.18.0.10. Решение этой проблемы называется преобразованием сетевых адресов (NAT). Принцип работы, следующий - перед отправкой во внешнюю сеть пакеты, отправленные контейнерами, заменяют свои исходные IP-адреса (source IP addesses) на адрес внешнего интерфейса хоста. Хост также будет отслеживать все существующие сопоставления (mapping) и по прибытии будет восстанавливать IP-адреса перед пересылкой пакетов обратно в контейнеры. Звучит сложно, но у меня для вас хорошие новости! Нам нужна всего одна команда, чтобы добиться требуемого результата:

$ sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/16 ! -o br0 -j MASQUERADE

Команда довольно проста. Мы добавляем новое правило в таблицу nat цепочки POSTROUTING с просьбой выполнить MASQUERADE всех исходящих пакетов из сети 172.18.0.0/16, но не через интерфейс моста.

Проверьте подключение:

$ sudo nsenter --net=/var/run/netns/netns0$ ping -c 2 8.8.8.8PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=43.2 ms64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=36.8 ms--- 8.8.8.8 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 2msrtt min/avg/max/mdev = 36.815/40.008/43.202/3.199 ms
$ sudo nsenter --net=/var/run/netns/netns0$ ping -c 2 8.8.8.8PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=43.2 ms64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=36.8 ms--- 8.8.8.8 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 2msrtt min/avg/max/mdev = 36.815/40.008/43.202/3.199 ms

Помните, что политика iptables по умолчанию - ACCEPT для каждой цепочки, она может быть довольно опасной в реальных условиях:

sudo iptables -S-P INPUT ACCEPT-P FORWARD ACCEPT-P OUTPUT ACCEPT

В качестве хорошего примера Docker вместо этого ограничивает все по умолчанию, а затем разрешает только для известных маршрутов:

$ sudo iptables -t filter --list-rules-P INPUT ACCEPT-P FORWARD DROP-P OUTPUT ACCEPT-N DOCKER-N DOCKER-ISOLATION-STAGE-1-N DOCKER-ISOLATION-STAGE-2-N DOCKER-USER-A FORWARD -j DOCKER-USER-A FORWARD -j DOCKER-ISOLATION-STAGE-1-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT-A FORWARD -o docker0 -j DOCKER-A FORWARD -i docker0 ! -o docker0 -j ACCEPT-A FORWARD -i docker0 -o docker0 -j ACCEPT-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2-A DOCKER-ISOLATION-STAGE-1 -j RETURN-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP-A DOCKER-ISOLATION-STAGE-2 -j RETURN-A DOCKER-USER -j RETURN$ sudo iptables -t nat --list-rules-P PREROUTING ACCEPT-P INPUT ACCEPT-P POSTROUTING ACCEPT-P OUTPUT ACCEPT-N DOCKER-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 5000 -j MASQUERADE-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER-A DOCKER -i docker0 -j RETURN-A DOCKER ! -i docker0 -p tcp -m tcp --dport 5005 -j DNAT --to-destination 172.17.0.2:5000$ sudo iptables -t mangle --list-rules-P PREROUTING ACCEPT-P INPUT ACCEPT-P FORWARD ACCEPT-P OUTPUT ACCEPT-P POSTROUTING ACCEPT$ sudo iptables -t raw --list-rules-P PREROUTING ACCEPT-P OUTPUT ACCEPT

Настроим сетевой доступ из внешнего мира в контейнеры (port publishing)

Публикация портов контейнеров для некоторых (или всех) интерфейсов хоста - популярная практика. Но что на самом деле означает публикация порта?

Представьте, что у нас есть сервис, работающий внутри контейнера:

$ sudo nsenter --net=/var/run/netns/netns0$ python3 -m http.server --bind 172.18.0.10 5000

Если мы попытаемся отправить HTTP-запрос этому сервису с хоста, все будет работать (ну, есть связь между корневым пространством имён и всеми интерфейсами контейнера, почему бы и нет?):

# From root namespace$ curl 172.18.0.10:5000<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"># ... omitted lines ...

Однако, если бы мы получили доступ к этому серверу из внешнего мира, какой IP-адрес мы бы использовали? Единственный IP-адрес, который мы можем знать, - это адрес внешнего интерфейса хоста eth0:

$ curl 10.0.2.15:5000curl: (7) Failed to connect to 10.0.2.15 port 5000: Connection refused

Таким образом, нам нужно найти способ перенаправить все пакеты, поступающие на порт 5000 интерфейса eth0 хоста, на адрес172.18.0.10:5000. Или, другими словами, нам нужно опубликовать порт 5000 контейнера на интерфейсе eth0 хоста.

# External trafficsudo iptables -t nat -A PREROUTING -d 10.0.2.15 -p tcp -m tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000# Local traffic (since it doesn't pass the PREROUTING chain)sudo iptables -t nat -A OUTPUT -d 10.0.2.15 -p tcp -m tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000

Кроме того, нам нужно включить iptables intercepting traffic over bridged networks (перехватывать трафик bridged networks):

sudo modprobe br_netfilter

Время проверить!

curl 10.0.2.15:5000<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"># ... omitted lines ...

Разбираемся в работе Docker network drivers

Но что же вам сделать теперь со всеми этими бесполезными знаниями? Например, мы могли бы попытаться разобраться в некоторых сетевых режимах Docker!

Начнем с режима --network host. Попробуйте сравнить вывод следующих команд ip link и sudo docker run -it --rm --network host alpine ip link. Сюрприз, они совпадут! Таким образом host mode Docker просто не использует изоляцию сетевого пространства имён и контейнеры работают в корневом сетевом пространстве имён и совместно используют сетевой стек с хост-системой.

Следующий режим, который нужно проверить, - это --network none. Вывод команды sudo docker run -it --rm --network none alpine ip link показывает только один сетевой интерфейс обратной loopback. Это очень похоже на наши наблюдения за только что созданным сетевым пространством имен. То есть до того момента, когда мы добавляли какие-либо veth устройства.

И последнее, но не менее важное: режим --network bridge (по умолчанию), это именно то, что мы пытались воспроизвести в этой статье.

Сети и rootless контейнеры

Одной из приятных особенностей диспетчера контейнеров podman является его ориентация на rootless контейнеры. Однако, как вы, вероятно, заметили, в этой статье мы использовали много эскалаций sudo и без root-прав настроить сеть невозможно. При настройке сетей rootful контейнеров Podman очень близок к Docker. Но когда дело доходит до rootless контейнеров, Podman полагается на проект slirp4netns:

Начиная с Linux 3.8, непривилегированные пользователи могут создавать network_namespaces (7) вместе с user_namespaces (7). Однако непривилегированные сетевые пространства имен оказались не очень полезными, потому что для создания пар veth (4) в пространствах имен хоста и сети по-прежнему требуются привилегии root (иначе доступ в Интернету будет отсутствовать).

slirp4netns позволяет получить доступ из сетевое пространства имен в Интернет непривилегированным пользователям, подключая устройство TAP в сетевом пространстве имен к стеку TCP/IP usermode (slirp).

Сеть rootless контейнера весьма ограничена: технически сам контейнер не имеет IP-адреса, потому что без привилегий root невозможно настроить сетевое устройство. Более того, проверка связи (ping) из rootless контейнера не работает, поскольку в нем отсутствует функция безопасности CAP_NET_RAW, которая необходима для работы команды ping.

Заключение

Рассмотренный в этой статье подход к организации сети контейнеров является лишь одним из возможных (ну, пожалуй, наиболее широко используемым). Есть еще много других способов, реализованных через официальные или сторонние плагины, но все они сильно зависят от средств виртуализации сети Linux. Таким образом, контейнеризацию по праву можно рассматривать как технологию виртуализации.

Подробнее..

Поэтапное преобразование виртуализованных нагрузок в контейнеры OpenShift

18.03.2021 14:16:42 | Автор: admin

Унаследованные приложения, как правило, имеют монолитную архитектуру и запускаются на одной или нескольких виртуальных машинах. Некоторые из таких систем легче поддаются модернизации, поскольку в мире контейнеров для них есть неплохие аналоги (EAP, Spring Boot и т.д.). Однако большие классические приложения на .Net, работающие под IIS на Windows-сервере, модернизировать гораздо сложнее, тем более за одну итерацию. Но благодаря OpenShift Virtualization такие ВМ-нагрузки можно импортировать в OpenShift как есть и затем контейнеризировать их поэтапно.

В OpenShift виртуальные машины являются привилегированными гражданами и имеют ровно те же возможности, что и podы, включая обращение к другим объектам и предоставление доступа к себе через конечные точки служб (service endpoints). Поэтому выполнив первичный перенос ВМ-приложения в OpenShift, его затем можно поэтапно модернизировать, а заодно и расширять функционал.

Стратегия миграции Shift and Modernize

Чтобы показать, как это делается, мы для примера возьмем приложение .Net, работающее под IIS на виртуалке Windows Server, импортируем его в OpenShift Virtualization, а затем поэтапно контейнеризуем все его логические слои. Обратите внимание, что стратегия shift and modernize подходит и для других связок операционная системасвязующее ПО.

Этап 1. Импорт ВМ в OpenShift Virtualization

Импорт ВМ в OpenShift возможен несколькими способами. Для виртуальных машин VMware можно использоватьвстроенный инструментарий миграции, который позволяет подключиться к экземпляру VSphere и напрямую импортировать эти виртуалки в OpenShift Virtualization. Для других платформ виртуализации, включая Hyper-V и Xen, можно использовать virt-v2v, чтобы конвертировать образ ВМ в формат, поддерживаемый OpenShift Virtualization, а затем импортировать этот образ, используя методы описанные здесь (EN).

Виртуальная машина запускается с помощью Yaml-конфигурации, базовый вариант которой можно найтиздесь. Этот Yaml-файл содержит определение ВМ, а также объектов service и route, плюс, некоторые функциональные конфигурации для более эффективной работы Windows-ВМ на платформе OpenShift Virtualization.

Нас интересует следующее секция:

 features: acpi: {} apic: {} hyperv: reenlightenment: {} ipi: {} synic: {} synictimer: {} spinlocks: spinlocks: 8191 reset: {} relaxed: {} vpindex: {} runtime: {} tlbflush: {} frequencies: {} vapic: {} evmcs: {} # do not use evmcs if testing with nested virt

После применения этого yaml, мы получаем доступ к графическому интерфейсу Windows UI через VNC Console, которую нам дает OpenShift Virtualization.

Кроме того, теперь у нас есть доступ к приложению через exposed route.

Этап 2. Контейнеризация UI приложения

Не всегда можно мигрировать всё сразу, особенно в случае больших приложений. Например, этому могут препятствовать зависимости от библиотек, которые есть в классическом .NET, но отсутствуют в .Net Core. В этом случае код приложения придется доработать.

И поскольку это можно делать поэтапно, мы начнем с веб-интерфейса и после того, как переведем UI-слой на .Net Core, упакуем его в контейнерный образ для OpenShift. Этот новый UI-pod будет потреблять API, которые предоставляются старым сайтом, работающем под IIS на виртуальной машине.

Приведенный ниже Dockerfile компилирует ваш код .Net Core и создает runtime-образ. Это также можно сделать через сборки S2I.

# https://hub.docker.com/_/microsoft-dotnet-coreFROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS buildWORKDIR /source# copy csproj and restore as distinct layersCOPY ./source .RUN dotnet restore# copy and publish app and librariesCOPY . .RUN dotnet publish -c release -o /app --no-restore# final stage/imageFROM mcr.microsoft.com/dotnet/core/aspnet:3.1WORKDIR /appCOPY --from=build /app .ENTRYPOINT ["dotnet", "ClientListUI.dll"]

Для сборки и отправки этого образа в реестр можно использовать podman. Затем остается только развернуть этот отвечающий за веб-интерфейс pod вместе с виртуальной машиной приложения.

Этап 3. Контейнеризация API

Вслед за UI-слоем мигрируем на .Net Core слой API и развернем его в виде отдельного podа. После чего на исходной виртуалке остается только база данных SQL Server. Соответствующим образом поправим сервис ВМ в части описания доступа:

kind: ServiceapiVersion: v1metadata: name: stage3-win2019-db-vm namespace: stage3 labels: kubevirt.io: virt-launcher kubevirt.io/domain: stage3-win2019-iis-vmspec:  ports: - protocol: TCP port: 1433 targetPort: 1433 selector: kubevirt.io: virt-launcher kubevirt.io/domain: stage3-win2019-iis-vm

Итак, теперь UI-pod нашего приложения вызывает API через service URL нашего API-podа, а тот в свою очередь использует service URL нашей виртуальной машины, чтобы делать запросы к базе данных.

Этап 4. Контейнеризация БД

Да, вы правильно поняли: миграция экземпляра MS SQL в контейнер RHEL. Лет пять назад такое и в голову бы никому не пришло, но сегодня это вполне рабочий вариант и подробнее узнать о том, как настроить и запустить MS SQL в контейнере, можно узнать здесь (EN).

После того, SQL-pod будет готов, остается настроить port forwarding, чтобы можно было работать с БД через MS SQL Management Studio или Azure Data Studio:

 oc get pod | grep sql | grep Runningsql2019-1-1-gp29h 1/1 Running 0 39h oc port-forward sql2019-1-1-gp29h 1433:1433Forwarding from 127.0.0.1:1433 -> 1433Forwarding from [::1]:1433 -> 1433Handling connection for 1433

Теперь можно переносить БД из экземпляра MS SQL на Windows-виртуалке в контейнер SQL Server. После чего, необходимо изменить строку подключения для API-podа приложения и указать в ней pod, где теперь живет ваш MS SQL.

Всё, приложение полностью, на 100% контейнеризовано, и виртуальную машину которую, мы перенесли на первом этапе, можно навсегда отключить.

Заключение

Поэтапная миграция ВМ-нагрузки по методу shift and modernize позволяет снизить технический долг, минимизировать любого рода регрессии, которые могут возникнуть входе этого процесса, ну и попутно расширить функционал приложения в рамках проводимой при такой миграции доработки кода.

Подробнее..

Перевод Шлюзы Java.Net в интеграционных продукциях InterSystems IRIS

06.10.2020 12:23:44 | Автор: admin

Шлюзы в InterSystems IRIS это механизм взаимодействия между ядром InterSystems IRIS и прикладным кодом на языках Java/.Net. С помощью шлюзов вы можете работать как с объектами Java/.NET из ObjectScript так и с объектами ObjectScript и глобалами из Java/.NET. Шлюзы могут быть запущены где угодно - локально, на удаленном сервере, в докере.

В этой статье я покажу, как можно легко разработать и контейнеризовать интеграционную продукцию с .Net/Java кодом. А для взаимодействия с кодом на языках Java/.Net будем использовать PEX, предоставляющий возможность реализовать любой элемент интеграционной продукции на языках Java/.Net.

Для нашего примера мы разработаем интеграцию с Apache Kafka.

Архитектура

Apache Kafka популярный брокер сообщений. В Kafka есть тема (topic) сообщения в которую издатели (publisher) пишут сообщения и есть подписчики (consumer) на темы, которые читают эти сообщения.

Сначала мы напишем Java бизнес-операцию которая будет пубиковать сообщения в Apache Kafka. Затем добавим бизнес-службу на языке C# которая будет сообщения читать, сохранять и передавать для дальнейшей обработки в InterSystems IRIS.

Наше решение будеть работать в докере и выглядит следующим образом:

Java Gateway

Прежде всего, разработаем Бизнес-Операцию на Java для отправки сообщений в Apache Kafka. Код может быть написан в любой Java IDE и выглядеть так:

  • Для разработки новой PEX бизнес-операции необходимо реализовать абстрактный класс com.intersystems.enslib.pex.BusinessOperation.

  • Публичные свойства класса это настройки нашего бизнес-хоста

  • Метод OnInit используется для установления соединения с Apache Kafka и получения указателя на InterSystems IRIS

  • OnTearDown используется для отключения от Apache Kafka (при остановке процесса).

  • OnMessage получает сообщение dc.KafkaRequest и отправляет его в Apache Kafka.

Теперь упакуем нашу бизнес-операцию в Docker контейнер.

Вот наш докер-файл:

FROM openjdk:8 AS builderARG APP_HOME=/tmp/appCOPY src $APP_HOME/srcCOPY --from=intersystemscommunity/jgw:latest /jgw/*.jar $APP_HOME/jgw/WORKDIR $APP_HOME/jar/ADD https://repo1.maven.org/maven2/org/apache/kafka/kafka-clients/2.5.0/kafka-clients-2.5.0.jar .ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar .ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar .ADD https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar .WORKDIR $APP_HOME/srcRUN javac -classpath $APP_HOME/jar/*:$APP_HOME/jgw/* dc/rmq/KafkaOperation.java &amp;&amp; \    jar -cvf $APP_HOME/jar/KafkaOperation.jar dc/rmq/KafkaOperation.classFROM intersystemscommunity/jgw:latestCOPY --from=builder /tmp/app/jar/*.jar $GWDIR/

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

FROM openjdk:8 AS builder

JDK8 это базовый образ, в котором мы будем компилировать наше приложение.

ARG APP_HOME=/tmp/appCOPY src $APP_HOME/src

Копируем исходный код из папки /src в /tmp/app.

COPY --from=intersystemscommunity/jgw:latest /jgw/*.jar $APP_HOME/jgw/

Копируем библиотеки Java Gateway в папку /tmp/app/jgw.

WORKDIR $APP_HOME/jar/ADD https://repo1.maven.org/maven2/org/apache/kafka/kafka-clients/2.5.0/kafka-clients-2.5.0.jar .ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar .ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar .ADD https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar .WORKDIR $APP_HOME/srcRUN javac -classpath $APP_HOME/jar/*:$APP_HOME/jgw/* dc/rmq/KafkaOperation.java &amp;&amp; \    jar -cvf $APP_HOME/jar/KafkaOperation.jar dc/rmq/KafkaOperation.class

Все зависимости скачаны - вызываем javac/jar для компиляции jar файла. Для реальных проектов рекомендуется использовать полноценную систему сборки maven или gradle.

FROM intersystemscommunity/jgw:latestCOPY --from=builder /tmp/app/jar/*.jar $GWDIR/

И, наконец, jar файлы копируются в базовый образ Java шлюза, который содержит все необходимые зависимости и обеспечивает запуск Java шлюза.

.Net Gateway

Далее разработаем службу .Net, которая будет получать сообщения от Apache Kafka. Код может быть написан в любой .Net IDE и выглядеть так.

Особенности:

  • Для разработки новой PEX бизнес-службы необходимо реализовать абстрактный класс InterSystems.EnsLib.PEX.BusinessService.

  • Публичные свойства класса это настройки нашего бизнес-хоста

  • Метод OnInit используется для установления соединения с Apache Kafka, подписки на темы Apache Kafka и получения указателя на InterSystems IRIS

  • OnTearDown используется для отключения от Apache Kafka (при остановке процесса)

  • OnMessage получает сообщения из Apache Kafka и отправляет сообщение класса Ens.StringContainer в целевые бизнес-хосты продукции

Теперь упакуем нашу бизнес-операцию в Docker контейнер.

Вот наш докер-файл:

FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS buildENV ISC_PACKAGE_INSTALLDIR /usr/irissysENV GWLIBDIR libENV ISC_LIBDIR ${ISC_PACKAGE_INSTALLDIR}/dev/dotnet/bin/Core21WORKDIR /sourceCOPY --from=store/intersystems/iris-community:2020.2.0.211.0 $ISC_LIBDIR/*.nupkg $GWLIBDIR/# copy csproj and restore as distinct layersCOPY *.csproj ./RUN dotnet restore# copy and publish app and librariesCOPY . .RUN dotnet publish -c release -o /app# final stage/imageFROM mcr.microsoft.com/dotnet/core/runtime:2.1WORKDIR /appCOPY --from=build /app ./# Configs to start the Gateway ServerRUN cp KafkaConsumer.runtimeconfig.json IRISGatewayCore21.runtimeconfig.json &amp;&amp; \    cp KafkaConsumer.deps.json IRISGatewayCore21.deps.jsonENV PORT 55556CMD dotnet IRISGatewayCore21.dll $PORT 0.0.0.0

Посмотрим, что здесь происходит:

FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build

Используем образ .Net Core 2.1 SDK для сборки нашего приложения.

ENV ISC_PACKAGE_INSTALLDIR /usr/irissysENV GWLIBDIR libENV ISC_LIBDIR ${ISC_PACKAGE_INSTALLDIR}/dev/dotnet/bin/Core21WORKDIR /sourceCOPY --from=store/intersystems/iris-community:2020.2.0.211.0 $ISC_LIBDIR/*.nupkg $GWLIBDIR/

Копируем библиотеки .Net Gateway из официального образа InterSystems IRIS:

# copy csproj and restore as distinct layersCOPY *.csproj ./RUN dotnet restore# copy and publish app and librariesCOPY . .RUN dotnet publish -c release -o /app

Компилируем нашу бизнес-операцию.

FROM mcr.microsoft.com/dotnet/core/runtime:2.1WORKDIR /appCOPY --from=build /app ./

Копируем библиотеки в финальный контейнер.

RUN cp KafkaConsumer.runtimeconfig.json IRISGatewayCore21.runtimeconfig.json &amp;&amp; \    cp KafkaConsumer.deps.json IRISGatewayCore21.deps.json

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

ENV PORT 55556CMD dotnet IRISGatewayCore21.dll $PORT 0.0.0.0

Запускаем шлюз на порту 55556, слушаем все сетевые интерфейсы.

Готово!

Вот полная конфигурация docker-compose, для запуска демо целиком (в том числе и UI для Apache Kafka, для просмотра сообщений).

Запуск демо

Для запуска демо локально:

Установите:

Выполните:

git clone https://github.com/intersystems-community/pex-demo.gitcd pex-demodocker-compose pulldocker-compose up -d

Выводы

  • В интеграционных продукциях InterSystems IRIS появилась возможность создавать любые элементы продукции на языках Java/.Net

  • Код на Java/.Net возможно вызывать из InterSystems ObjectScript и наоборот, код на InterSystems ObjectScript из Java/.Net

  • Генерация прокси классов больше не требуется

  • Возможна как классическая поставка решения, так и поставка в Docker

Ссылки

Подробнее..

Перевод Разворачиваем модель машинного обучения с Docker Часть 1

04.08.2020 18:23:50 | Автор: admin
Перевод статьи подготовлен в преддверии старта базового и продвинутого курсов по машинному обучению.

Расширяем возможности для наших студентов. Теперь в OTUS есть целых два курса по Machine Learning: базовый и продвинутый. Оба курса стартуют в августе, в связи с чем мы приглашаем всех желающих на день открытых дверей в онлайн-формате, в рамках которого наш эксперт Дмитрий Сергеев (Senior Data Scientist в Oura) подробно расскажет о курсах, а также ответит на интересующие вопросы.


Наша основная задача как специалистов по Data Science это обработка данных, а также разработка и совершенствование моделей машинного обучения. Бытует мнение, что обработка данных самый трудоемкий этап во всем проекте, а точность модели определяет успех информационного продукта. Однако отрасль сейчас находится на переходном этапе от эпохи открытий к эпохе внедрения (Сверхдержавы в области искусственного интеллекта: Китая, Силиконовая Долина, а новый мировой порядок в этой сфере диктует Ли Кайфу). Сейчас картина становится шире, и фокус смещается с построения модели на предоставление модели пользователям в качестве сервиса и с производительности модели к ее бизнес-ценности. Самый известный пример здесь Netflix, который никогда не использовал модели победителей их соревнования на 1$ млн, несмотря на обещанное значительное повышение производительности, обеспечиваемое этими движками (Netflix Never Used Its $1 Million Algorithm Due To Engineering Costs WIRED).


От понимания к реальности (слайды с конференции Strata Data Kubeflow explained: Portable machine learning on Kubernetes)

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

Контейнеризация метод, который широко используется для развертывания программных продуктов как на облачной платформе, так и на локальном сервере. По сути, речь идет об упаковке кода и зависимостей в коробку, которая называется контейнером. Ниже приводится определение контейнера в контексте разработки программного обеспечения:

С сайта Docker

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

Docker это платформа, которая может помочь вам ускорить процесс разработки, контейнеризации, а также развертывания нашей модели машинного обучения в других средах. В этой серии статей я расскажу вам как хранить модель, использовать ее в качестве конечной точки API, контейнеризировать ваше ML-приложение и запускать его на движке Docker.

Вопрос первый Почему Docker?


Прежде чем мы начнем, вам нужно будет зарегистрироваться в Docker ID, если у вас его нет, а затем использовать этот ID для загрузки и установки Docker на свой компьютер.

Когда я только начинал свою работу в банке, мне поручили проект, который был связан с обработкой данных, и первый MVP (минимальный жизнеспособный продукт) нужно было доставить за месяц. Звучит напряжно, но мы в команде используем методологию Agile в процессе разработки всех основных продуктов, и основной целью этого MVP было проверить гипотезу о практичности и эффективности продукта (более подробную информацию про методологию Agile вы найдете в книге Эрика Риса Lean Startup). Мой менеджер хотел, чтобы я развернул свою модель на его ноутбуке, то есть запустил ее и использовал для прогнозирования.

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

  • На какой операционной системе нужно будет запускать модель, ведь он пользуется Macbook и ThinkPad? Я мог бы, конечно, спросить его об этом, но предположим, что в тот момент жизни мой босс был очень противным, и не хотел, чтобы я знал эту информацию. (Эта мысль здесь для того, чтобы вы осознали проблему зависимости от операционной системы, а так мой босс правда хороший человек.)
  • Второй вопрос: Установлен ли у него Python?. Если да, то какая версия, 2 или 3? Какая именно: 2.6, 2.7 или 3.7?
  • А как насчет необходимых пакетов, таких как scikit-learn, pandas и numpy? Установлены ли у него те же версии, что и у меня на машине?

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

  1. Установить Python.
  2. Установить все пакеты.
  3. Настроить переменные среды.
  4. Перенести код на машину.
  5. Запустить код с необходимыми параметрами.

Для выполнения всех этих шагов понадобится много усилий, а при запуске кода в различных средах есть риск несовместимости.

Итак, если у вас уже установлен и запущен Docker, вы можете открыть терминал и выполнить следующую команду:

docker run --rm -p 5000:5000 datascienceexplorer/classifier

Через пару минут вы должны увидеть нечто похожее в своем терминале:

* Serving Flask app "main" (lazy loading)* Environment: production   WARNING: Do not use the development server in a production environment.   Use a production WSGI server instead.* Debug mode: off* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Теперь откройте свой любимый браузер и перейдите по этому адресу:

http://localhost:5000/apidocs/

Нажмите на строчку predict из API, а затем на кнопку try-out справа, интерфейс будет выглядеть следующим образом:


Страница Swagger для API на бэкенде

Помните стандартный набор данных Цветы Ириса, с которым вы игрались? Это небольшое приложение поможет вам спрогнозировать вид цветка на основе информации о некоторых измерениях на основе классификационной модели. На самом деле вы уже используете мою модель машинного обучения как сервис, и все, что вы установили это лишь Docker, и мне не понадобилось ставить Python или какие-то пакеты на вашу машину.

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

DevOps Data Science


Теперь, надеюсь, я вас достаточно замотивировал, чтобы продолжать чтение, и если вы просто захотите пропустить эти части и перейти сразу к коду, то все в порядке, поскольку это значит, что вы хотите контейнеризировать свою модель машинного обучения с Docker и предоставлять ее как сервис. Однако сейчас нам придется немного остановиться и отложить все материалы про машинное обучение и Docker в сторону, чтобы подумать о DevOps в Data Science и о том, зачем он там вообще нужен.

Что же такое DevOps?


Из Википедии
DevOps это совокупность практик, сочетающих в себе разработку программного обеспечения и информационно-технологическое обслуживание, целью которых является сокращение жизненного цикла разработки систем и обеспечение непрерывной поставки высококачественного программного обеспечения.
Целью разработчиков программного обеспечения является своевременная доставка кода со всем необходимым функционалом, в то время как удобство использования, надежность, масштабируемость, сетевая часть, брандмауэр, инфраструктура и т.д. часто остаются операционными проблемами. Из-за разнящихся конечных целей и, вероятно, ключевых показателях эффективности, эти команды обычно не уживаются под одной крышей. Поэтому DevOps-специалист мог бы сыграть роль связующего звена и помочь этим командам работать сообща, или даже взять на себя ответственность обеих сторон, чтобы в итоге получилась одна команда, ведущая разработку от начала до конца. В конце концов, вы ведь не можете просто отдать свой компьютер клиенту, поскольку на нем-то код работает как надо.
Но с Jupyter notebook я счастлив!!!
У специалистов по Data Science история аналогичная, поскольку опять же вы не можете просто взять и отдать свой ноутбук с запущенным Jupyter Notebook, чтобы клиент просто пользовался им. Нам нужен способ использовать модель так, чтобы она могла обслуживать большое количество пользователей в любое время в любом месте и подниматься с минимальным временем простоя (удобство использования, надежность, масштабируемость).

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

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

Хранение обученной модели


Еще в университете мы узнали, что проект Data Science состоит из шести этапов, как показано на картинке ниже. Если автоматизация и развертывание модели на продакшене является нашей конечной целью, то как же отправить модель на стадию развертывания?


Шесть этапов Data Science-проекта

Самый простой способ, который только можно придумать это скопировать все из нашего notebook, вставить в файл с расширение .py и запустить его. Однако каждый раз, когда нам нужно будет сделать прогноз, мы будем запускать этот файл и заново на тех же данных обучать модель. Если такой подход хоть как-то применим для простых моделей с небольшим обучающим набором данных, он не будет эффективен для сложных моделей с большим количеством обучающих данных (подумайте о том, сколько времени вам понадобится для обучения модели ANN или CNN). Здесь имеется в виду, что, когда пользователь отправляет запрос модели на прогнозирование, ему придется ждать от нескольких минут до нескольких часов, чтобы получить результат, поскольку много времени уйдет на выполнения этапа обучения модели.

Как хранить модель сразу после того, как она обучится?


В большинстве случаев модель машинного обучения в Python будет храниться в памяти как объект Python во время выполнения кода, а затем будет удалена после окончания работы программы. Если бы мы могли сохранить этот объект на жестком диске сразу после того, как модель обучится, то в следующий раз, когда нам понадобится сделать прогноз, мы сможем просто загрузить готовую модель в память и не проходить этапы инициализации и обучения. В информатике процесс преобразования объекта в поток байтов для хранения называется сериализацией. В Python это может быть легко реализовано с помощью пакета под названием pickle, который изначально имеет нативную поддержку Python. Python-разработчики еще называют pickling процесс сериализации объекта с помощью pickle.

В Jupyter notebook вы можете с легкостью сохранить объект модели (в моем случае knn) в файл pkl, который располагается в том же каталоге, что и код:

import picklewith open('./model.pkl', 'wb') as model_pkl:  pickle.dump(knn, model_pkl)

Сохранение модели в текущую директорию

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

Первый шаг пройден, вы сохранили обученную модель. Дальше мы будем переиспользовать модель для прогнозирования, но об этом уже во второй части статьи.



Узнать подробнее о:





Читать ещё


Подробнее..

Перевод Разворачиваем модель машинного обучения с Docker Часть 2

17.08.2020 18:04:48 | Автор: admin


Расширяем возможности для наших студентов. Теперь в OTUS есть целых два курса по Machine Learning: базовый и продвинутый. Оба курса стартуют в августе, в связи с чем мы предлагаем вам посмотреть запись дня открытых дверей в онлайн-формате, а также приглашаем записаться на бесплатные уроки: Пайплайн работы с задачей ML и Поиск аномалий в данных.


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

Для того чтобы протестировать модель, в той же папке, где находится файл model.pkl, создайте файл main.py с этим кодом:

import pickle# Импортируем все пакеты, которые необходимы для вашей моделиimport numpy as npfrom sklearn.neighbors import KNeighborsClassifier# Загружаем модель в памятьwith open('./model.pkl', 'rb') as model_pkl:   knn = pickle.load(model_pkl)# Неизвестные данные (создаем новое наблюдение для тестирования)unseen = np.array([[3.2, 1.1, 1.5, 2.1]])result = knn.predict(unseen)# Выводим результаты на консольprint('Predicted result for observation ' + str(unseen) + ' is: ' + str(result))


Повторное использование модели для прогнозирования.

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

Traceback (most recent call last): File "main.py", line 4, in <module>   from sklearn.neighbors import KNeighborsClassifierImportError: No module named sklearn.neighbors


Это связано с тем, что используемый нами пакет недоступен в среде, в которой вы запускаете файл. Это значит, что среда, используемая для разработки модели (conda), не идентична среде выполнения (среда python за пределами conda), и это можно рассматривать как потенциальную проблему при запуске нашего кода в других средах. Я специально хотел, чтобы вы увидели эту ошибку, чтобы помочь вам узнать о проблеме, и еще раз подчеркнуть важность использования контейнеров для развертывания нашего кода, чтобы избежать подобных проблем. На данный момент вы можете просто вручную установить все необходимые пакеты с помощью команды pip install. Мы вернемся сюда позже, чтобы сделать это автоматически.

После установки всех пакетов и успешного запуска файла модель должна быстро вернуть следующее сообщение:

Predicted result for observation [[3.2 1.1 1.5 2.1]] is: [1]


Как вы можете здесь увидеть, для тестирования модели мы используем захардкоженные неизвестные данные. Эти числа представляют собой длину чашелистика, его ширину, длину лепестка и его ширину соответственно. Однако, поскольку мы хотим предоставлять нашу модель как сервис, она должна быть представлена как функция, принимающая запросы, содержащие эти четыре параметра, и возвращающая результат прогноза. Затем эту функцию можно использовать для сервер API (бекенда) или развернуть в бессерверной среде выполнения, такой как Google Cloud Functions. В этом руководстве мы попытаемся вместе создать сервер API и поместить его в контейнер Docker.


Как работает API?


Давайте поговорим о том, как сегодня устроены веб-приложения. В большинстве веб-приложений есть два основных компонента, которые покрывают почти все функции, необходимые приложению: фронтенд и бекенд. Фронтенд ориентирован на обслуживание интерфейса (веб-страницы) для пользователя, а фронтенд сервер часто хранит HTML, CSS, JS и другие статические файлы, такие как изображения и звуки. С другой стороны, бекенд сервер будет обрабатывать всю бизнес-логику, которая отвечает на любые запросы, отправленные из фронтенда.


Иллюстрация структуры веб-приложений.

Вот что произойдет, когда вы откроете Medium в своем браузере.

  1. Ваш браузер отправляет HTTP-запрос на адрес medium.com. Потребуется ряд операций на DNS-сервере, маршрутизаторах, межсетевых экранах и т. д., но для простоты этой статьи мы их проигнорируем.
  2. Фронтенд сервер отправляет обратно * .html, * .css, * .js и все другие файлы, необходимые для рендеринга веб-страницы в вашем браузере.
  3. Теперь в браузере вы должны увидеть страницу Medium и начать с ней взаимодействовать. Допустим, вы только что нажали кнопку clap (похлопать) на статье.
  4. Скрипты (javascript) в вашем браузере отправят HTTP-запрос на бекенд сервер с id истории. URL-адрес запроса сообщит бекенду, какое действие следует выполнить. В этом примере он скажет бекенду обновить количество хлопков в истории с id XXXXXXX.
  5. Бекенд программа (которая, может быть написана на любом языке) получит текущее количество хлопков в базе данных и увеличит его на единицу.
  6. Затем бекенд программа отправляет актуальное количество хлопков обратно в базу данных.
  7. Бекенд отправляет новое количество хлопков в браузер, чтобы его можно было отразить в интерфейсе.


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

Теперь я хочу, чтобы вы сосредоточили внимание на синих стрелках на рисунке выше. Это HTTP-запросы (отправленные из браузера) и HTTP-ответы (полученные браузером или отправленные в браузер). Компоненты, обрабатывающие запросы от браузера и возвращающие ответы на бекенд сервере, называются API.

Ниже приведено определение API:

Из Вебопедии

Интерфейс прикладного программирования (API application program interface) это набор процедур, протоколов и инструментов для создания программных приложений. По сути, API определяет, как должны взаимодействовать программные компоненты.


Создаем наш собственный API!


Существует множество фреймворков, которые помогают нам создавать API с помощью Python, включая Flask, Django, Pyramid, Falcon и Tornado. Преимущества и недостатки, а также сравнение этих структур, перечислены здесь. В этом уроке я буду использовать Flask, но техника и рабочий процесс остаются такими же, как и для других, и в качестве альтернативы вы вполне можете использовать на этом этапе свой любимый фреймворк.

Последнюю версию Flask можно установить через pip с помощью этой команды:

pip install Flask


Все, что вам нужно сделать сейчас это превратить код из предыдущего шага в функцию и зарегистрировать для нее эндпоинт API после инициализации приложения Flask. По умолчанию приложение Flask запускается на локалхосте (127.0.0.1) и будет прослушивать запросы на порту 5000.

import pickle# Импортируем все пакеты, которые необходимы для вашей моделиimport numpy as npimport sysfrom sklearn.neighbors import KNeighborsClassifier# Импортируем Flask для создания APIfrom flask import Flask, request# Загружаем обученную модель из текущего каталогаwith open('./model.pkl', 'rb') as model_pkl:   knn = pickle.load(model_pkl)# Инициализируем приложение Flaskapp = Flask(__name__)# Создайте конечную точку API@app.route('/predict')def predict_iris():   # Считываем все необходимые параметры запроса   sl = request.args.get('sl')   sw = request.args.get('sw')   pl = request.args.get('pl')   pw = request.args.get('pw')# Используем метод модели predict для# получения прогноза для неизвестных данных   unseen = np.array([[sl, sw, pl, pw]])   result = knn.predict(unseen)  # возвращаем результат    return 'Predicted result for observation ' + str(unseen) + ' is: ' + str(result)if __name__ == '__main__':   app.run()


Представление вашей модели как API

На терминале вы должны увидеть следующее:

* Serving Flask app "main" (lazy loading)* Environment: production  WARNING: This is a development server. Do not use it in a production deployment.  Use a production WSGI server instead.* Debug mode: off* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)


Откройте браузер и введите в адресной строке следующий запрос:

http://localhost:5000/predict?sl=3.2&sw=1.1&pl=1.5&pw=2.1

Если в вашем браузере появляется что-то подобное, поздравляем! Теперь вы предоставляете свою модель машинного обучения в качестве службы с эндпоинтом API.

Predicted result for observation [['3.2' '1.1' '1.5' '2.1']] is: [1]

Тестирование API с помощью Postman


Недавно мы использовали наш браузер для быстрого тестирования API, но это не очень эффективный способ. Например, мы могли бы не использовать метод GET, а вместо этого использовать метод POST с токеном аутентификации в заголовке, а сделать так, чтобы браузер отправлял такой запрос, непросто. При разработке программного обеспечения Postman широко используется для тестирования API-интерфейсов и совершенно бесплатен для базового использования.


Пользовательский интерфейс Postman (со страницы загрузки Postman)
После загрузки и установки Postman откройте инструмент и следуйте инструкциям ниже, чтобы отправить запрос.


Отправка GET запроса с помощью Postman

  1. Убедитесь, что вы выбрали GET запрос, поскольку мы настраиваем API только для получения GET запроса. Это может не сработать, если вы случайно выберете POST запрос.
  2. Вставьте сюда URL вашего запроса.
  3. В этой таблице необходимо обновить параметры запроса. Не стесняйтесь поиграть с этими параметрами и посмотреть, что вы получите в результате.
  4. Нажмите кнопку Отправить, чтобы отправить запрос на наш сервер API.
  5. Здесь будет отображаться ответ нашего сервера.
  6. Вы также можете проверить дополнительную информацию об этом HTTP-ответе. Это может быть очень полезно для отладки.


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

Читать первую часть.
Подробнее..

Категории

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

  • Имя: Макс
    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