\documentclass{article}

\input{settings/common-preamble}
\input{settings/bmstu-preamble}
\input{settings/fancy-listings-preamble}
\author{Мещеринова Ксения Владимировна}
\title{Телематика}
\date{2023-02-08}

\begin{document}
\sloppy
\fontsize{14}{18}\selectfont
\maketitle
\tableofcontents

\section{Введение}
DevOps -- стратегия разработки ПО, призванная устранить разрыв между разработчиками, и другими командами. Методология автомтизации технологических процессов сборки, настройки и развёртывания программного обеспечения. Методология предполагает активное взаимодействие специалистов по разработке со специалистами по информационно-технологическому обсулуживанию и взаимную интеграцию их технологических процессов друг в друга, для обеспечения высокого качества программного продукта.

Методологии разработки - waterfall (последовательный переход от одного этапа к другому), agile (scrum, lean) -- гибкая методология, система идей. Ключевой принцип - разработка через короткие итерации.

Водопадная модель разработки (Waterfall-разработка):
\begin{itemize}
\item Системные и программные требования: закрепляются в PRD (product requirements documents, документ требований к продукту).
\item Анализ: воплощается в моделях, схемах и бизнес-правилах.
\item Дизайн: разрабатывается внутренняя архитектура ПО, способы реализации требований; Не только интерфейс, и внешний вид ПО, но и его внутренняя структурная логика.
\item Кодинг: непосредственно пишется код программы, идёт интеграция ПО.
\item Тестирование: баг-тестеры (тестировщики) проверяют финальный продукт, занося в трекеры сведения о дефектах кода программы или функционала. В случае ошибок и наличия времени/финансов происходит исправление багов.
\item Операции: продукт адаптируется под разные операционные системы, регулярно обновляется для исправления обнаруженных пользователями багов и добавления функционала. В рамках стадии также осуществляется техническая поддержка клиентов.
\end{itemize}

Основные принципы гибкой методологии:
\begin{itemize}
\item Люди и взаимодействие важнее процессов и инструментов
\item работающий продукт важнее исчерпывающей документации
\item сотрудничество с заказчиком важнее согласования условий контракта
\item готовность к изменениям важнее следования первоначальному плану.
\end{itemize}

Обычно ИТ-команда это разработчики(Dev), тестировщики(QA), группа эксплуатации(Ops). Толчком к появлению девопс стало появление микросервисов. Цели девопс -- Сокращение времени выхода на рынок, надёжность (снижение частоты отказов новых релизов), сокращение времени выполнения исправлений, уменьшение количества времени на восстановления (в случае сбоя).

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

Жизненный цикл приложения

\begin{itemize}
\item \textbf{Планирование} помогает обеспечить командам гибкость и прозрачность
  \begin{itemize}
  \item представляют, определяют и описывают функции и возможности создаваемых приложений
  \item отслеживают ход работы на низком и высоком уровнях детализации
  \item создают журналы невыполненной работы, отслеживая ошибки, и так далее.
  \end{itemize}
\item \textbf{Разработка} включает написание, тестирование, проверку и интеграцию кода участниками команды. Быстро внедряют инновации, автоматизируя рутинные действия, а также запускают итерации с маленьким шагом при помощи автоматического тестирования и непрерывной интеграции.
\item \textbf{Доставка} -- это процесс последовательного и надёжного развёртывания приложений в рабочих средах. Этап доставки также включает развёртывание и настройку полностью управляемой базовой инфраструктуры, лежащей в основе этих сред.
  \begin{itemize}
  \item определяют процесс управления выпусками
  \item устанавливают автоматические шлюзы, с помощью которых приложения перемещаются между этапами, пока не станут доступными клиентам
  \end{itemize}
\item \textbf{Эксплуатация}.
  \begin{itemize}
  \item обслуживание
  \item мониторинг
  \item устранение неполадок приложений в рабочих средах
  \end{itemize}
  внедряя методики девопс, различные подразделения стремятся обеспечить надёжность системы и высокую доступность, свести простои к нулю, а также повысить уровень безопасности и усовершенствовать управление.
\end{itemize}

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

методики девопс
\begin{itemize}
\item непрерывная доставка (CI/CD)
\item управление версиями (git)
\item гибкая разработка (DevOps)
\item инфраструктура как код (IaC)
\item управление конфигурацией
\item непрерывный мониторинг
\end{itemize}

\begin{figure}[H]
  \centering
  \includegraphics[width=12cm]{04-telematics-devops.png}

  \includegraphics[width=12cm]{04-t-devops-table.jpg}
\end{figure}

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

Три способа развёртывания облачных служб:
\begin{itemize}
\item Публичное облако -- всё принадлежит облачному поставщику.
\item частное облако -- ресурсы только одной компании, локаный ЦОД (иногда аутсорс ЦОД)
\item гибридное облако
\end{itemize}

модели обслуживания:
\begin{itemize}
\item IaaS -- infrastructure (серверы, виртуальные машины, итд с оплатой по мере использования);
\item PaaS -- platform (среда по управлению, доставке, итд, упрощает разработчикам настройку связок);
\item Saas -- software (предоставление уже разработанного ПО как услуги);
\end{itemize}

В облаке, с помощью девопс возможно:
\begin{itemize}
\item создание собственных облачных приложений
\item тестирование и сборка приложений
\item хранение, резервное копирование, восстановление данных
\item анализ данных
\item доставка ПО по запросу
\end{itemize}

DevOps-инженер -- высококвалифицированный специалист, который отвечает за автоматизацию всех этапов создания приложений и обеспечивает взаимодействие программистов и системных администраторов. Прорабатывает сборку, доставку и тестирование. Build-инженер, Release-инженер, Automation-инженер, Security-инженер.

\begin{itemize}
\item [+] высокий заработок
\item [+] востребованность
\item [+] интересные задачи
\item [+] перспектива карьерного роста
\item [-] непрерывное обучение (\textit{а минус ли это? прим. Овчинников})
\item [-] необходимость знать много из разных областей
\item [-] возможны стрессовые ситуации и высокая нагрузка
\end{itemize}

Необходимые знания:
\begin{itemize}
\item Основы программирования (базовый уровень, несколько языков)
\item освоиться в принципах работы ОС
\item понимать облачные и гибридные решения
\item разбираться в системах оркестрации
\item освоить принципы работы микросервисов
\item понимать принципы работы с системами конфигурации
\end{itemize}

Используемые инструменты -- Jenkins, Docker, Kubernetes, Git, Приложения для управления инфраструктурой (Terraform), платформенные и облачные сервисы, утилиты мониторинга и оповещений.

\section{Система контейнеризации Docker}
\subsection{Виртуализация и контейнеризация}

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

До появления микросервисов и контейнеров повсеместно использовались монолитные приложения на основе систем виртуализации.

Особенности монолитных приложений
\begin{itemize}
\item много зависимостей
\item долгая разработка
\item повсеместное использование виртуализации
\end{itemize}

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

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

\subsection{Виртуализация}
Гипервизор -- это инструмент, обеспечивающий параллельное управление несколькими ОС на хосте.
\begin{figure}[H]
  \centering
  \fontsize{12}{1}\selectfont
  \includesvg[scale=1.01]{pics/04-t-00-hyperv.svg}
\end{figure}

Типы гипервизоров
Гипервизоры:
\begin{itemize}
\item аппаратные -- VMWare ESX, Citrix XenServer, MS Hyper-V;
\item устанавливаемые поверх базовой ОС -- MS Virtual PC, VMWare Workstation, VirtualBox;
\item гибридные -- Citrix XenServer, Microsoft Hyper-V.
\end{itemize}

Назрела необходимость в ином подходе к построению архитектуры приложений, при котором ядро ОС поддерживают несколько изолированных экземпляров пользовательского пространства вместо одного (namespaces)\footnote{namespace -- это функция ядра Linux, позволяющая изолировать и виртуализировать глобальные системные ресурсы множества процессов.}. Возникновение контейнеризации -- контейнерной виртуализации. Контейнеризация использует ядро хост системы, оставаясь при этом не менее функциональной и обеспечивающей необходимую изоляцию.

Контейнерная виртуализация -- это способ, при котором виртуальная среда запускается прямо из ядра хотовой ОС (то есть без установки другой ОС). В данном случае изоляцию ОС и приложений поддерживает контейнер. Контейнер содержит всё, что нужно для запускаемого в нём приложения: код, библиотеки, инструменты и настройки. Всё это упаковано в отдельный образ, работу которого запускает контейнерный движок.

В случае с контейнерами у нас есть базовая аппаратная инфраструктура (железа компьютера), ОС и движок, установленный на этой ОС. Движок управляет контейнерами, которые работают с библиотеками и зависимостями сами, в одиночку. В случае виртуальной машины у нас есть ОС на базовом оборудовании (наше железо), затем гипервизор, а затем виртуальные машины. У каждой ВМ внутри своя ОС. Контейнеры загружаются быстрее и работают эффективнее.

Проблемы контейнеризации. Для контейнеров используется виртуализация на уровне ядра, то есть от гипервизора можно отказаться. Однако:
\begin{itemize}
\item контейнер использует ядро хост системы, а отсюда проблемы с безопасностью;
\item в контейнере может быть запущен экземпляр ОС только с тем же ядром, что и у хост ОС.
\end{itemize}

Возможно получить доступ к возможностям Windows и Linux одновременно при помощи WSL.

Как решить проблемы проблемы контейнеризации:
\begin{itemize}
\item следование принципу единственной ответственности (Single responsibility principle)
\item Всё необходимое должно быть в самом контейнере
\item Образы должны быть небольшого размера
\item контейнер должен быть эфемерным
\end{itemize}

Контейнеризаторы приложений (Docker, LXC)

Докер -- платформа автоматизации и доставки приложений с открытым исходным кодом. Платформа позволяет быстрее тестировать и выкладывать приложения, запускать на одной машине требуемое количество контейнеров.
\begin{itemize}
\item сервер dockerd
\item API
\item CLI
\end{itemize}

Компоненты докер
\begin{itemize}
\item хост -- хост ПК, компьютер, на котором работает докер.
\item демон -- фоновый процесс, работающий на хосте постоянно и ожидающий команды управления. Имеет информацию обо всех контейнерах на хосте. Демон знает всё о контейнерах, запущенных на одном хосте -- сколько всего контейнеров, какие из них работают, где хранятся образы и так далее.
\item клиент -- клиент при помощи с котрого пользователь взаимодействует с демоном. Это может быть консоль, API или графический интерфейс.
\item образ -- неизменяемый образ приложения (можно представить как установочный диск)
\item контейнер -- развёрнутое на основе образа и запущенное приложение.
\item докерфайл -- файл-инструкция для сборки докер-образа. Строки файла это слои образа. Инструкции обрабатываются последовательно.
\item docker registry -- репозиторий, в котором хранятся образы (докерхаб)
\end{itemize}

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

Контейнер -- уже собранное, настроенное и запущенное на основе образа приложение в изолированное среде.

\subsection{Принципы работы Docker-образов}
Образ -- это единица, используемая для распространения приложений. Контейнер -- имеет стандартизированный формат, который используется как группой эксплуатации

ПО, упакованное в контейнер:
\begin{itemize}
\item код приложения
\item системные пакеты
\item двоичные файлы
\item библиотеки
\item файлы конфигурации
\item ОС, работающую в контейнере
\end{itemize}
Программное обеспечение, упакованное в контейнер, не ограничивается приложениями, создаваемыми разработчиками. ОС узла -- это OC, в которой выполняется модуль Docker. Контейнеры Docker, работающие в Linux, совместно используют ядро ОС узла и не нуждаются в ОС контейнера, если двоичный код может напрямую обращаться к ядру ОС.

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

Например, разрабатываем портал отслеживания заказов, который будут использоваться торговыми точками некоторой компании. Нам нужно рассмотреть полный стек ПО длоял выполнения этого веб-приложения. MVC .Net Core, и мы планируем развернуть его с помощью Nginx в качестве обратного прокси-сервера в Ubuntu Linux. Все эти программные компоненты входят в образ контейнера

Образ контейнера -- это переносимый пакет, содержащий ПО. При запуске он становится контейнером. Образ неизменен, после сборки образа, невозможно внести в него изменения.

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

ОС контейнера - это ОС, которая входит в упакованный образ. В контейнер можно включать различные версии ОС Linux или Windows Такая гибкость позволяет получать доступ K определенным возможностям ОС или устанавливать дополнительное ПО, требуемое приложениям.

Мы создаём образ для описанного веб-приложения. Расположим дистрибутив Ubuntu как базовый образ поверх файловой системы загрузки. Далее устанавливаем Nginx, который таким образом будет поверх Ubuntu. Последний доступный для записи слой создается после запуска контейнера из образа. Этот слой не сохраняется при уничтожении контейнера.

Что такое стековая файловая система унификации (unionfs)
Для создания образов Docker используется Unionfs. Unionfs -- это файловая система, позволяющая объединять в стек несколько каталогов, При этом содержимое представляется как объединенное. Однако на физическом уровне оно хранится раздельно.

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

Образы Docker - это файлы большого размера, которые изначально сохраняются на компьютере. Для управления ими нужны специальные средства. Интерфейс командной строки (CLI) Docker позволяет управлять образами:
\begin{itemize}
\item выполнять их сборку
\item получать их список
\item удалять и запускать образы
\end{itemize}

Dockerfile -- это текстовый файл с инструкциями для сборки и запуска образа Docker.
\begin{itemize}
\item В файле определяется базовый и родительский образ, используемый для создания образа;
\item команды для обновления базовой ОС и установки дополнительного программного обеспечения;
\item службы, такие как хранилище и конфигурация сети
\item команда, выполняемая при запуске контейнера.
\end{itemize}

Базовый образ использует Docker scratch -- пустой образ, который не создает слой файловой системы. Он предполагает, что запускаемое приложение может напрямую использовать ядро ОС узла.

Родительский образ это образ контейнера, из которого создается наш - образ. Например, в нашем случае, вместо того чтобы создавать образ из cratch, a затем устанавливать Ubuntu, лучше использовать образ, уже основанный на Ubuntu. Можно даже использовать образ, в котором уже установлен Nginx.

Родительский образ чаще всего -- предустановленная ОС или другая основа.

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

Пример Dockerfile для создания образа для веб-сайта.

\begin{itemize}
\item [] \textbf{FROM} - задает базовый (родительский) образ.
\item [] \textbf{RUN} выполняет команду и создаёт слой образа. Используется для установки контейнер пакетов. B
\item [] \textbf{COPY} - копирует в контейнер файлы и папки.
\item [] \textbf{EXPOSE} - задает определенный порт в контейнере
\item [] \textbf{CMD} описывает команду с аргументами, которую нужно выполнить когда контейнер будет запущен. Аргументы могут быть переопределены при запуске контейнера. В файле может присутствовать лишь одна инструкция СMD.
\item [] \textbf{WORKDIR} задаёт рабочую директорию для следующей инструкции.
\item [] \textbf{ENTRYPOINT} - указывает, какой процесс будет - выполняться при запуске контейнера из образа.
\end{itemize}

\begin{verbatim}
# Step 1: Specify the parent Image for the new image 
FROM ubuntu:18.04

# Step 2: Update OS packages and Install additional software
RUN apt -y update && apt install -y .........

# Step 3: Configure Nginx environment 
CMD service nginx start

# Step 4: Configure Nginx environment
COPY ./default/etc/nginx/sites-available/default

STEP 5: Configure work directory
WORKDIR /app

#STEP 6: Copy website code to container
COPY./website/..

#STEP 7: Configure network requirements
EXPOSE 80:8080

#STEP 8: Define the entrypoint of the process in the container
ENTRYPOINT ["dotnet", "website.dll"]

\end{verbatim}
\subsection{Сборка образа Docker}
Для сборки образов Docker служит команда \code{docker build}. Предположим, что для сборки образа мы используем приведенное выше Определение Dockerfile. Ниже представлен пример команды сборки.

\begin{verbatim}
docker build-t temp-ubuntu
\end{verbatim}

В предыдущем примере сборки последнее сообщение было:

\begin{verbatim}
"Successfully tagged temp-ubuntu: latest"
\end{verbatim}

Тег образа -- это текстовая строка, используемая для указания версии образа.

\subsection{Управление контейнерами}
Зачем присваивать контейнерам имена? Это позволяет запускать несколько экземпляров контейнеров, созданных из одного образа. Имена контейнеров уникальны.Т.е. указанное имя не может использоваться повторно для создания другого контейнера. Единственный способ повторно использовать определенное имя -- удалить предыдущий контейнер.

Контейнер имеет ЖЦ, которым можно управлять и отслеживать состояние контейнера.

\begin{itemize}
\item создание
\item работа
\item приостановка
\item возобновление работы
\item запуск
\item остановка
\item перезапуск
\item принудительная остановка
\item удаление
\end{itemize}

Чтобы вывести список выполняющихся контейнеров используется команда
\begin{verbatim}
docker ps
\end{verbatim}

Чтобы просмотреть все контейнеры во всех состояниях, передайте аргумент \code{-a}. Docker автоматически настраивает локальный реестр образов на компьютере. Просмотреть образы в реестре с помощью команды:

\begin{verbatim}
docker images
\end{verbatim}

Удалить образ из локального реестра Docker с помощью команды \code{docker rmi}. Указывается имя или ID образа, который требуется удалить. Допустим, удалим образ с именем temp-Ubuntu:version-1.0:

\begin{verbatim}
docker rmi temp-Ubuntu:version-1.0
\end{verbatim}

Если образ используется контейнером, удалить ero нельзя. Команда \code{docker rmi} возвращает сообщение об ошибке, в котором указывается контейнер, использующий образ.

Для удаления контейнера служит команда \code{docker rm}

\begin{verbatim}
docker rm happy_wilbur
\end{verbatim}

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

Для перезапуска контейнера используется команда docker restart

\begin{verbatim}
docker restart happy_wilbur
\end{verbatim}

Так контейнер получает команду stop, а затем команду start.

Приостанавливает контейнер команда docker pause.

\begin{verbatim}
docker pause happy_wilbur
\end{verbatim}

Приостановка контейнера приводит к приостановке всех процессов. Эта команда позволяет контейнеру продолжить процессы в дальнейшем. Команда docker unpause отменяет приостановку всех процессов в указанных контейнерах.

\subsection{Флаги команды \code{docker run}}

Если перед флагом стоит два тире -- то это его полная форма, флаг с одним тире -- это сокращённый вариант некоего флага. Действуют они одинаково. Например, \code{-р} -- это сокращённая форма флага \code{--port}; \code{-i} (\code{--interactive}) -- поток STDIN поддерживается в открытом состоянии даже если контейнер к STDIN не подключён; \code{-t} (\code{--tty}) -- соединяет используемый терминал с потоками STDIN и STDOUT контейнера.

Для того чтобы получить возможность взаимодействия с контейнером через терминал нужно совместно использовать флаги \code{-i} и \code{-t}.

\begin{verbatim}
docker run -it tmp-ubuntu
\end{verbatim}

Запускает контейнер команда \code{docker run}. Для запуска контейнера из образа нужно просто указать его имя или идентификатор.

\begin{verbatim}
docker run -d tmp-ubuntu
\end{verbatim}

Здесь для запуска контейнера в фоновом режиме следует добавить флаг \code{-d}.

\code{-p} (\code{--port}) порт -- это интерфейс, благодаря которому контейнер взаимодействует с внешним миром. Например: конструкция \code{1000:8000} перенаправляет порт Docker 8000 на порт 1000 компьютера, на котором выполняется контейнер. Если в контейнере работает некое приложение, способное выводить что-то в браузер, то, для того, чтобы к нему обратиться, в нашем случае можно перейти в браузере по адресу \code{localhost:1000}.

\code{-d} (\code{--detach}) запуск контейнер в фоновом режиме. Это позволяет использовать терминал, из которого запущен контейнер, для выполнения других команд во время работы контейнера.

\subsection{Работа с данными в Docker}
Конфигурация хранилища контейнера Docker

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

Есть два основных способа обмена данными с контейнером -- тома (volume).

Контейнеры могут быть подключены...

Например, внутри контейнера по пути лежит файл индекс.хтмл.

Для монтирования данных используются следующие параметры:

\begin{itemize}
\item [] \code{-V} или \code{--Volume}
\item [] \code{--mount}
\end{itemize}
Их различие в том, что мount более явно заставляет указывать источник монтирования папки. В случае параметра -V указывается два пути "откуда куда". В случае --mount это именованные параметры разделенные запятыми. Пример работы обоих:

\begin{verbatim}
-v /home/docker_data:/usr/share/nginx/html
-mount type=bind, \
       source=/home/docker_data, \
       destination=/usr/share/nginx/html
\end{verbatim}

Так выглядит запуск контейнера с проброшенной папкой:

\begin{verbatim}
docker run -d--name nginx_vol1 
  -v /home/docker_data:/usr/share/nginx/html:ro nginx

docker run -d--name nginx_vol2 \
  -mount type=bind, \
     source=/home/docker_data, \
     destination=/usr/share/nginx/html,ro nginx
\end{verbatim}

B mount мы используем следующие параметры:
\begin{itemize}
\item type -- со значением 'bind' говорит, что мы монтируем папку или файл
\item source -- источник т.е. папка или файл, который мы хотим подключить к контейнеру
\item destination -- папка или файл внутри контейнера
\end{itemize}

\subsection{Работа с сетью в Docker}
Конфигурация сети Docker по умолчанию обеспечивает изоляцию контейнеров в узле Docker. Это позволяет создавать и настраивать приложения, которые могут безопасно взаимодействовать друг с другом.

Docker предоставляет следующие конфигурации сети:
\begin{itemize}
\item Мост (Bridge)
\item Узел (Host)
\item Macvlan
\item Overlay
\item none
\end{itemize}

Сеть типа мост -- конфигурация по умолчанию к контейнерам при запуске, если иное не указано при запуске. Эта сеть является внутренней частной сетью, используемой контейнером. Она изолирует сеть узла от сети контейнера.

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

ПРИМЕР: Порт 80 контейнера необходимо сопоставить с доступным портом узла. В узле открыт порт 8080:

\begin{verbatim}
--publish 8080:80
\end{verbatim}

Узел (Host) позволяет запускать контейнер непосредственно в сети узла. Эта конфигурация фактически устраняет изоляцию между узлом и контейнером на сетевом уровне. В предыдущем примере предположим, что используем конфигурацию типа Host. Доступ будет по IP-адресу узла. То есть теперь используем порт 80 вместо сопоставленного порта. Помните, что контейнер может использовать только те порты, которые еще не используются узлом.

Macvlan. Контейнер подключается при помощи виртуального интерфейса, подключенного к физическому. При этом у каждого из них есть свой МАС- адрес. В этом случае у контейнеров есть прямой доступ к интерфейсу и субинтерфейсу (vlan) хоста.

Overlay. Использование этого драйвера позволяет строить сети на нескольких хостах с Docker (обычно на Docker Swarm кластере). У контейнеров также есть свои адреса сети и подсети, и они могут напрямую обмениваться данными, даже если они располагаются физически на разных хостах.

\section{Когда следует использовать контейнеры Docker?}
Переносимость приложений. Контейнеры могут выполняться практически везде: на Настольных компьютерах, физических серверах, в виртуальных машинах и в облаке. Такая совместимость со средами выполнения позволяет легко перемещать контейнерные приложения между разными средами. Так как контейнеры требуют меньше ресурсов, увеличение времени запуска или завершения работы сказывается на виртуальных машинах. Благодаря этому упрощается и ускоряется повторное развертывание.

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

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

Контейнеры Docker поддерживаются на многих облачных платформах.

\section{Когда НЕ следует использовать контейнеры Docker?}
использование ядро ОС хоста, которое может стать объектом атаки. для обеспечения безопасности нужно принимать во внимание конфигурацию хранения и сети, в некоторых случаях целесообразнее использовать виртуальные машины.

Управление контейнерами сложнее, чем ВМ, можем узнать состояние, но получить журнал за определённое время - не очень просто (\code{docker stats} это поток данных, поэтому их обработка и хранение не производится).

\section{docker-compose}
Надстройка над docker, применяется для многоконтейнерных приложений. позволяет запускать множество сервисов при помощи одной команды. docker применяется для управления отдельными контейнерами или сервисами. compose -- для одновременного управления несколькими контейнерами.

compose написан на python, конфигурация в yaml-файлах.

в составе docker desktop (Windows, mac) уже есть, на linux надо доставить руками.

докер-композ
нгинкс
 докерфайл
пхп
 докерфайл
ввв
 индекс.хтмл

подменяем нгинкс.конф

докер-композ ямл - описывает процесс загрузки и настройки контейнеров.

\subsection{Основные команды}
К основным командам docker можно отнести:
\begin{itemize}
\item docker pull-скачивает образ
\item docker run - запускает контейнер на основе образа
\item docker ps - вызывает список запущенных контейнеров
\item docker exec - позволяет выполнять команды в контейнере
\item docker stop - останавливает контейнер
\item docker rm-удаляет контейнер
\item docker rmi - удаляет образ
\end{itemize}

docker-compose
\begin{itemize}
\item build -- сборка
\item up -- запуск
\item up -d -- запуск в фоне
\item down -- остановка и удаление
\item stop -- остановка сервисов
\item restart -- перезапуск
\end{itemize}


\section{Оркестрация контейнеров}
Оркестраторы управляют ЖЦ контейнеров микросервисных приложений. Задачи оркестратора:
\begin{itemize}
\item подготовка инфраструктуры и развёртывание -- установка приложения и его зависимостей на сервер, включая подготовку этого сервера -- установку библиотек, служб, и так далее.
\item Разделение ресурсов -- Для развертывания приложения кластере разработки требуется B выделить вычислительные ресурсы сервера для различных процессов: это объемы памяти (RAM) центрального процессора (CPU). И Устанавливаются запрашиваемые и предельные параметры, правила при достижении контейнерами ресурсных лимитов, различные ограничения. Это важно для поддержания приложения в рабочем состоянии и сведения затрат к минимуму.
\item Масштабирование контейнеров на основе рабочих нагрузок -- простой излишних ресурсов приводит к издержкам, а недостаток -- к нестабильно йработе приложения. Регулировать объёмы используемых ресурсов позволяет масштабирование, основанное на анализе нагрузок. Может быть ручным или автоматизированным.
\item Балансировка нагрузок -- Автоматический анализ и распределение рабочих нагрузок на сервер целиком и контейнеры в частности. Балансировка оптимизирует использование ресурсов, увеличивает пропускную способность каналов связи, минимизирует Время отклика и помогает избежать перегрузки отдельных ресурсов.
\item Маршрутизация трафика -- Чтобы приложение было доступно из интернета, нужно настроить правильное распределение трафика из внешней сети по контейнерам и нужным сервисам.
\item Мониторинг состояния контейнеров -- Эта функция позволяет видеть, какие контейнеры и их образы запущены и где, какие команды используются в контейнерах, какие контейнеры потребляют слишком много ресурсов и почему.
\item Обеспечение безопасного взаимодействия между контейнерами -- На основе непрерывной оценки кластеров, узлов и реестра контейнеров предоставляются данные о неверных конфигурациях и других уязвимостях, которые могут представлять угрозу, а также рекомендации по устранению Выявленных угроз.
\end{itemize}

\subsection{Системы оркестрации контейнеров}
\subsubsection{Kubernetes (k8s)}

Эта платформа открытым исходным кодом считается отраслевым C стандартом. Позволяет автоматизировать масштабирование, развертывание с помощью шаблонов управление рабочей нагрузкой сервисами и контейнеров. Поддерживает ОС: Windows, macOS, Linux. 

Предлагает:
\begin{itemize}
\item мониторинг сервисов и распределение нагрузки,
\item автомонтирование гибкой системы хранения,
\item автоматизированные откаты и развертывания,
\item автораспределение нагрузки,
\item горизонтальное автомасштабирование,
\item автоперезапуск, замена и завершение работы отказавших контейнеров,
\item управление конфигурацией и конфиденциальной информацией, самовосстановление.
\end{itemize}

\subsection{OpenShift Container Platform}
Платформа в формате PaaS для разработки, развертывания и управления не только контейнерными, но классическими приложениями И И их компонентами в режиме самообслуживания. Позволяет автоматизировать их в физических, виртуальных и общедоступных, частных и гибридных облачных средах. Поддержка ОС: Linux.

Предлагает:
\begin{itemize}
\item встроенные средства кластеризации и оркестрации;
\item автомасштабирование;
\item балансировку нагрузки;
\item совместимость созданных на платформе приложений с любыми другими платформами, поддерживающими контейнеры Docker.
\end{itemize}

\subsection{Nomad}
Легкий в поддержке, гибкий оркестратор для развертывания и управления контейнерными и классическими приложениями в физической или облачной среде. Поддерживает ОС: Linux, Windows, macOS. B основном Nomad управляет развертыванием и перезапускает контейнеры при обнаружении ошибок. Этого часто оказывается достаточно для небольших проектов.

Предлагает:
\begin{itemize}
\item простое управление,
\item хорошую экосистему встроенную интеграцию с другими продуктами (например, Terraform),
\item автоматизацию переноса приложения из монолитной в микросервисную архитектуру,
\item масштабируемость,
\item возможность развернуть все кластерное приложение с несколькими контейнерами с помощью плагина из каталога одним щелчком мыши.
\end{itemize}

\subsection{Docker Swarm}
Это «родная», базовая система кластеризации и оркестрации контейнеров Docker. **Docker Swarm** - базовая система кластеризации и оркестрации контейнеров Docker. Взаимодействие с кластером происходит через команды Docker, a управление действиями - через менеджер Swarm. Поддержка ОС: \textbf{Windows, macOS, Linux}.

Кластер \textbf{Swarm (Docker Swarm Cluster)} состоит из узлов (нод), которые делят на два типа:
\begin{itemize}
\item управляющая нода (\textbf{manager}). Это нода, которая принимает запросы и распределяет задачи между всеми нодами в кластере.
\item рабочие (\textbf{worker}) ноды (узлы)
\end{itemize}

\textbf{Docker Swarm} - \textbf{встроенное} в Docker решение по контейнерной оркестрации. Более легкое в освоении, чем Kubernetes.
Swarm - стандартный оркестратор для Docker контейнеров, доступный вам, если у вас установлен сам Docker.

Что потребуется для освоения:
\begin{itemize}
\item Иметь опыт работы с Docker и Docker Compose. 
\item Настроенный Docker registry.
\item Swarm не очень любит работать с локальными образами.
\item Несколько виртуальных машин для создания кластера, хотя по факту кластер может состоять из одной ВМ, но так будет нагляднее.
\end{itemize}

\subsection{Устройство}
Основу кластера Docker Swarm представляют управляющие (manager) и рабочие (worker) узлы
\begin{figure}[H]
  \centering
  \includegraphics[width=12cm]{04-telematics-ustr.png}
\end{figure}
Docker Swarm состоит из менеджеров и воркеров. Менеджеры определяют, на каких воркерах и как будут работать контейнеры.

\subsection{Термины}
Для того чтобы пользоваться Docker Swarm надо запомнить несколько типов сущностей:
\textbf{Node} - это BM, на которых установлен Docker. Есть manager и worker ноды.
\textbf{Manager нода} управляет worker нодами. Она отвечает за workers a также за их создание/обновление/удаление сервисов на workers, масштабирование и поддержку в требуемом состоянии. Worker ноды используются только для выполнения поставленных задач и не могут управлять кластером.
\textbf{Stack} - это набор сервисов, которые логически связаны между собой. По сути это набор сервисов, которые мы описываем в обычном compose файле. Части Stack (services) могут располагаться как на одной ноде, так и на разных.
\textbf{Service} это как раз то, из чего состоит Stack. Service является описанием - того, какие контейнеры будут создаваться. Как Docker-compose.yaml. Кроме стандартных полей Docker B режиме Swarm поддерживает ряд дополнительных, большинство из которых находятся внутри секции deploy.
\textbf{Task} - это непосредственно созданный контейнер, который Docker создал на основе той информации, которую мы указали при описании Service. Swarm будет следить за состоянием контейнера и при необходимости его перезапускать или перемещать на другую ноду.

\begin{figure}[H]
  \centering
  \includegraphics[width=12cm]{04-telematics-swarm.png}
\end{figure}

\subsection{Создание кластера}
Для того чтобы кластер работал корректно, необходимо:
\begin{itemize}
\item IP-адрес управляющей ноды должен быть назначен сетевому интерфейсу, доступному операционной системе хоста. Все ноды в Swarm должны подключаться к менеджеру по IP-адресу.
\item Открытые протоколы и порты между хостами
\item Должны быть доступны следующие порты. В некоторых системах они открыты по умолчанию.
  \begin{itemize}
  \item \textbf{ТСР-порт 2377} для управления кластером.
  \item \textbf{Порт ТСР и UDP 7946} для связи между узлами.
  \item \textbf{UDP-порт 4789} для оверлейного сетевого трафика.
  \end{itemize}
\end{itemize}
\textbf{docker swarm init} необходимо выполнить на всех worker node, чтобы присоединить их в только что созданный кластер. Если все прошло успешно:

\textbf{docker node ls} Ha manager Hоде в консоли, вы увидите что-то подобное:

Чтобы убрать ноду из кластера, необходимо зайти на ВМ, которая является ею, и выполнить команду: \textbf{docker swarm leave}

Если затем зайти на manager ноду и выполнить docker node ls, вы заметите, что статус у нее поменялся с Ready на Down (это может занять некоторое время). Swarm больше не будет использовать данную ноду для размещения контейнеров.

Для того чтобы окончательно удалить ноду, надо выполнить (на manager node): \textbf{docker node rm stage}

\begin{figure}[H]
  \centering
  \includegraphics[width=12cm]{04-telematics-stack.png}
\end{figure}

В начале необходимо достать image из registry и только затем развернуть в наш кластер:

\begin{verbatim}
docker pull docker-registry.ru:5000/ptm:stage;
docker stack deploy --with-registry-auth \
    -c ./docker-compose.stage.yaml stage;*
\end{verbatim}

Команды выполняются на manager node. Флаг --with-registry-auth позволяет передать авторизационные данные на worker ноды, для того чтобы использовался один и тот же образ из регистра. Stage это имя нашего стэка. Посмотреть список стэков можно с помощью: 

docker stack ls Список сервисов внутри стэка:

docker stack services stage

Удалить стэк можно следующим образом: docker stack rm stage

Можно запускать и отдельно взятые сервисы, например:

\begin{verbatim}
docker service create --name nginx --replicas 3 nginx:alpine; 
docker service ps nginx;
\end{verbatim}

В данном примере мы запустили сервис nginx в виде 3 экземпляров, которые Swarm раскидал по 3 нодам.

\begin{figure}[H]
  \centering
  \includegraphics[width=12cm]{04-telematics-ps.png}
\end{figure}

Удалить сервис можно следующим образом: docker service rm nginx

Для того чтобы увидеть более подробную информацию по сервису в виде JSON: \verb|docker service inspect stage_back|. Тут также можно увидеть, какие порты слушает сервис, в каких сетях участвует, какой у него статус и т.д.

\textbf{Label Swarm} по умолчанию развертывает сервисы на любой доступной ноде/нодах, но как правило нам необходимо развертывать их на конкретной ноде или на специфической группе. Для этого нужны labels. Например, у нас есть stage и prod окружение. Stage используется для внутренней демонстрации продукта, а prod группой разработки.

Для каждого из окружений у есть compose файл: docker-compose.stage.yaml и docker-compose.prod.yaml. По умолчанию Swarm будет раскидывать service произвольно по нодам. А нам нужно, чтобы сервис для stage запускался только на stage BM и аналогично для prod.

В начале, добавим еще одну ноду в кластер, в качестве worker

\begin{verbatim}
# заходим по ssh на еще одну виртуальную 
# машину и добавляем ее в кластер 
docker swarm join --token \
  SWMTKN-1-54k2k418tw2jejuwm3inq6crp4ow6xogswihcc5azg7oc
# выполняем команду на manager ноде:
docker node ls
\end{verbatim}

Затем необходимо разметить ноды:
\begin{verbatim}
docker node update --label-add TAG=stage stage 
docker node update --label-add TAG=prod prod-1
\end{verbatim}

Используя hostname виртуальных машин, мы ставим label. Для того чтобы убедиться, что все прошло успешно, необходимо выполнить команду: docker node inspect stage. Ищем раздел Spec. Labels, где мы должны увидеть label, который добавили:

\begin{verbatim}
"Spec": {
       "Labels": {
           "TAG": "stage"
         },
         "Role": "worker",
         "Availability": "active"
}
\end{verbatim}

После чего в compose файл необходимо добавить директиву placement, где прописывается условие, которое указывает, на каких нодах разворачивать данный сервис: Для docker-compose.prod.yaml будет аналогично, но с тэгом prod (однако для внешнего мира надо использовать другой порт, например 4004). После развертывания данных Stacks сервисы разворачиваются только на нодах с определенным тэгом.

docker-compose.stage.yaml

\begin{verbatim}
version: "3.9"
services:
back:
image: docker-registry.ru:5000/pta:stage
ports:
-"4003:4083"
environment:
12: "Europe/Moscow"
extra_hosts:
- host docker. internal:host-gateway command: make server_start volumes:
- /p/ptm/config/config-yaml:/p/ptm/config/config.yaml
- /p/ptm/stat/web:/p/ptm/stat/web.
#swarm deploy:
placement:
constraints:
- "node.labels. TAG==stage”
\end{verbatim}

\subsection{Маршрутизация}
В данный момент у нас 3 ноды: manager нода, нода для stage версии приложения и еще одна для разработки.

docker node ls

Если развернуть наш стэк для docker-compose.prod.yaml на том же 4003 порту, что и для уже запущенного стэка docker-compose.stage.yaml, то получим ошибку, связанную с тем, что порт уже занят.

Почему это произошло? И более того, если мы зайдем на ВМ prod-1 и Сделаем curl 127.0.0.1:4003, то увидим, что наш сервис доступен, хотя на этой ноде мы еще не успели ничего развернуть?

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

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

?ФОТО

Поэтому для docker-compose.prod.yaml нужно использовать любой другой публичный порт, отличный от того, который указан в docker-compose.stage.yaml.

Отключить автоматическую маршрутизацию трафика можно с помощью mode: host при декларации ports:

В данном случае запрос, который придет на порт 4004, Swarm будет направлять только на контейнер текущей ноде никуда И больше.

Настройка mode (напрямую это не относится к маршрутизации). Она может принимать следующие значения: global или replicated (по умолчанию):

\begin{verbatim}
*deploy:
      mode: global
deploy:
      mode: replicated
   replicas: A*
\end{verbatim}

Если global это означает, что данный сервис будет запущен ровно в одном экземпляре на всех возможных нодах. A replicated означает, что п-ое кол-во контейнеров для данного сервиса будет запущено на всех доступных нодах.

\textbf{Zero downtime deployment} Это возможность организовать «бесшовную» смену контейнеров во время развертывания. Это возможно и в Docker-compose, но надо держать дополнительную реплику контейнера (даже, если по нагрузке требуется всего одна) и на уровне балансировщика переключать трафик с одного контейнера на другой. C Docker Swarm это все не нужно, необходимо лишь немного скорректировать конфигурацию сервиса. Для начала нужно добавить директиву healthcheck:

\begin{verbatim}
*healthcheck:
test: curl -ss http://127.0.0.1:4004/ptm/api/healthcheck ||
echo 1
interval: 30s
timeout: 3s
retries: 12*
\end{verbatim}

Она предназначена, чтобы Docker мог определить, корректно ли работает контейнер. test - результат исполнения этой команды Docker использует для определения корректно
ли работает контейнер. 
*interval* - с какой частотой проверять состояние. В данном случае каждые 30 секунд.
*timeout* - таймаут для ожидания выполнения команды.
*retries* - количество попыток для проверки состояния сервера внутри контейнера.

После добавления директивы healthcheck в compose file мы увидим в Status информацию о состоянии контейнера:
**docker container Is**

После развертывания стэка контейнер сначала имеет статус **starting** (сервер внутри нашего контейнера запускается), а через некоторое время получит статус **healthy** (сервер запустился), в противном случае **unhealthy**.
**Docker** в режиме **Swarm** не просто отслеживает жизненное состояние контейнера, но и в случае перехода в состояние **unhealthy** попытается пересоздать контейнер.   

**Настройки для обновления контейнера:**
**replicas** - количество контейнеров, которые необходимо запустить
для данного сервиса.
Директива \verb|update_config| описывает каким образом сервис должен обновляться:
**parallelism** количество контейнеров для одновременного - обновления. По умолчанию данный параметр имеет значение 1 - контейнеры будут обновляться по одному. 0 - обновить сразу все контейнеры. В большинстве случаев это число должно быть меньше, чем общее количество реплик сервиса.

\begin{verbatim}
deploy:
    replicas: 1
update_config:
parallelism: 1
order: start-first
failure_action: rollback
delay: 10s
\end{verbatim}

order - порядок обновления контейнеров. По умолчанию ptop-first, сначала текущий контейнер останавливается, а затем запускается новый. Для «бесшовного» обновления нужно использовать start- first. В этом случае вначале запускается новый контейнер, а затем выключается старый.
\verb|failure_action| - стратегия в случае сбоя. Вариантов несколько: continue, rollback, или pause (по умолчанию).
delay - задержка между обновлением группы контейнеров.

**Docker secrets**
Swarm предоставляет хранилище для приватных данных (secrets), которые необходимы контейнерам. Это используется для хранения логинов, паролей, ключей шифрования и токенов доступа от внешних систем, БД и т.д.
**Создадим yaml файл с «секретным» токеном:**
* example.yaml
\begin{verbatim}
token: sfsjksajflsf_secret*
\end{verbatim}

В данный момент у нас 3 ноды: manager нода, нода для stage версии приложения и еще одна для разработки.
**docker node 1s**

Если развернуть наш стэк для docker-compose.prod.yaml на том же 4003 порту, что и для уже запущенного стэка docker-compose.stage.yaml, то получим ошибку, связанную с тем, что порт уже занят.

Почему это произошло? И более того, если мы зайдем на ВМ prod-1 и Сделаем curl 127.0.0.1:4003, то увидим, что наш сервис доступен, хотя на этой ноде мы еще не успели ничего развернуть?

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

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

? ФОТО

Поэтому для docker-compose.prod.yaml нужно использовать любой другой публичный порт, отличный от того, который указан в docker-compose.stage.yaml.
Отключить
автоматическую маршрутизацию трафика можно с помощью mode: host при декларации ports:
В данном случае запрос, который придет на порт 4004, Swarm будет направлять только на контейнер текущей ноде никуда И больше.

Настройка **mode** (напрямую это не относится к маршрутизации). Она может принимать следующие значения: global или replicated (по умолчанию):

\begin{verbatim}
*deploy:
      mode: global
deploy:
      mode: replicated
   replicas: A*
\end{verbatim}

Если global это означает, что данный сервис будет запущен ровно в одном экземпляре на всех возможных нодах. A replicated означает, что п-ое кол-во контейнеров для данного сервиса будет запущено на всех доступных нодах.

**Zero downtime deployment**
Это возможность организовать «бесшовную» смену контейнеров во время развертывания.
Это возможно и в Docker-compose, но надо держать дополнительную реплику контейнера (даже, если по нагрузке требуется всего одна) и на уровне балансировщика переключать трафик с одного контейнера на другой.
C **Docker Swarm** это все не нужно, необходимо лишь немного скорректировать конфигурацию сервиса.
Для начала нужно добавить директиву healthcheck:

\begin{verbatim}
*healthcheck:
test: curl -ss http://127.0.0.1:4004/ptm/api/healthcheck ||
echo 1
interval: 30s
timeout: 3s
retries: 12*
\end{verbatim}

Она предназначена, чтобы Docker мог определить, корректно ли работает контейнер. test - результат исполнения этой команды Docker использует для определения корректно
ли работает контейнер. 
*interval* - с какой частотой проверять состояние. В данном случае каждые 30 секунд.
*timeout* - таймаут для ожидания выполнения команды.
*retries* - количество попыток для проверки состояния сервера внутри контейнера.

После добавления директивы healthcheck в compose file мы увидим в Status информацию о состоянии контейнера:
**docker container Is**

После развертывания стэка контейнер сначала имеет статус **starting** (сервер внутри нашего контейнера запускается), а через некоторое время получит статус **healthy** (сервер запустился), в противном случае **unhealthy**.
**Docker** в режиме **Swarm** не просто отслеживает жизненное состояние контейнера, но и в случае перехода в состояние **unhealthy** попытается пересоздать контейнер.   

**Настройки для обновления контейнера:**
**replicas** - количество контейнеров, которые необходимо запустить
для данного сервиса.
Директива \verb|update_config| описывает каким образом сервис должен обновляться:
**parallelism** количество контейнеров для одновременного - обновления. По умолчанию данный параметр имеет значение 1 - контейнеры будут обновляться по одному. 0 - обновить сразу все контейнеры. В большинстве случаев это число должно быть меньше, чем общее количество реплик сервиса.

\begin{verbatim}
deploy:
    replicas: 1
update_config:
parallelism: 1
order: start-first
failure_action: rollback
delay: 10s
\end{verbatim}

order - порядок обновления контейнеров. По умолчанию ptop-first, сначала текущий контейнер останавливается, а затем запускается новый. Для «бесшовного» обновления нужно использовать start- first. В этом случае вначале запускается новый контейнер, а затем выключается старый.
\verb|failure_action| - стратегия в случае сбоя. Вариантов несколько: continue, rollback, или pause (по умолчанию).
delay - задержка между обновлением группы контейнеров.

**Маршрутирзация**

В данный момент у нас 3 ноды: manager нода, нода для stage версии приложения и еще одна для разработки.
**docker node 1s**
Если развернуть наш стэк для docker-compose.prod.yaml на том же 4003 порту, что и для уже запущенного стэка docker-compose.stage.yaml, то получим ошибку, связанную с тем, что порт уже занят.
Почему это произошло? И более того, если мы зайдем на ВМ prod-1 и Сделаем curl 127.0.0.1:4003, то увидим, что наш сервис доступен, хотя на этой ноде мы еще не успели ничего развернуть?
Связано это с тем, что у Swarm имеется ingress сеть, которая используется для маршрутизации траффика между нодами. Если у сервиса есть публичный порт, то Swarm слушает его и в случае поступления запроса на него делает следующее: определяет есть ли контейнер на этой хост машине и если нет, то находит ноду, на которой запущен контейнер для данного сервиса, и перенаправляет запрос туда.

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

Поэтому для docker-compose.prod.yaml нужно использовать любой другой публичный порт, отличный от того, который указан в docker-compose.stage.yaml.
Отключить
автоматическую маршрутизацию трафика можно с помощью mode: host при декларации ports:
В данном случае запрос, который придет на порт 4004, Swarm будет направлять только на контейнер текущей ноде никуда И больше.

Настройка **mode** (напрямую это не относится к маршрутизации). Она может принимать следующие значения: global или replicated (по умолчанию):

\begin{verbatim}
*deploy:
      mode: global
deploy:
      mode: replicated
   replicas: A*
\end{verbatim}

Если global это означает, что данный сервис будет запущен ровно в одном экземпляре на всех возможных нодах. A replicated означает, что п-ое кол-во контейнеров для данного сервиса будет запущено на всех доступных нодах.

**Zero downtime deployment**
Это возможность организовать «бесшовную» смену контейнеров во время развертывания.
Это возможно и в Docker-compose, но надо держать дополнительную реплику контейнера (даже, если по нагрузке требуется всего одна) и на уровне балансировщика переключать трафик с одного контейнера на другой.
C **Docker Swarm** это все не нужно, необходимо лишь немного скорректировать конфигурацию сервиса.
Для начала нужно добавить директиву healthcheck:

\begin{verbatim}
*healthcheck:
test: curl -ss http://127.0.0.1:4004/ptm/api/healthcheck ||
echo 1
interval: 30s
timeout: 3s
retries: 12*
\end{verbatim}

Она предназначена, чтобы Docker мог определить, корректно ли работает контейнер. test - результат исполнения этой команды Docker использует для определения корректно
ли работает контейнер. 
*interval* - с какой частотой проверять состояние. В данном случае каждые 30 секунд.
*timeout* - таймаут для ожидания выполнения команды.
*retries* - количество попыток для проверки состояния сервера внутри контейнера.

После добавления директивы healthcheck в compose file мы увидим в Status информацию о состоянии контейнера:
**docker container Is**

После развертывания стэка контейнер сначала имеет статус **starting** (сервер внутри нашего контейнера запускается), а через некоторое время получит статус **healthy** (сервер запустился), в противном случае **unhealthy**.
**Docker** в режиме **Swarm** не просто отслеживает жизненное состояние контейнера, но и в случае перехода в состояние **unhealthy** попытается пересоздать контейнер.   

**Настройки для обновления контейнера:**
**replicas** - количество контейнеров, которые необходимо запустить
для данного сервиса.
Директива \verb|update_config| описывает каким образом сервис должен обновляться:
**parallelism** количество контейнеров для одновременного - обновления. По умолчанию данный параметр имеет значение 1 - контейнеры будут обновляться по одному. 0 - обновить сразу все контейнеры. В большинстве случаев это число должно быть меньше, чем общее количество реплик сервиса.
**order** - порядок обновления контейнеров. По умолчанию ptop-first, сначала текущий контейнер останавливается, а затем запускается новый. Для «бесшовного» обновления нужно использовать start- first. В этом случае вначале запускается новый контейнер, а затем выключается старый.
\verb|failure_action| - стратегия в случае сбоя. Вариантов несколько: continue, rollback, или pause (по умолчанию).
**delay** - задержка между обновлением группы контейнеров.

\begin{verbatim}
deploy:
    replicas: 1
    update_config:
    parallelism: 1
    order: start-first
    failure_action: rollback
    delay: 10s
\end{verbatim}

**Docker secrets**

**Swarm** предоставляет хранилище для приватных данных (secrets), которые необходимы контейнерам. Это используется для хранения логинов, паролей, ключей шифрования и токенов доступа от внешних систем, БД и т.д.
**Создадим yaml файл с «секретным» токеном:**
* example.yaml
\begin{verbatim}
token: sfsjksajflsf_secret*
\end{verbatim}

Создадим **secret** с именем \verb|back_config|:

\begin{verbatim}
docker secret create back_config example.yaml 
nys6v16j4d8ymmi f8755305
\end{verbatim}

docker secret is

\begin{verbatim}
*#inspect specific secret*
docker secret inspect back_config
"ID": "nys6v16j4d8ynnif875q6305",
"Version": [
"Index"; 24683
"CreatedAt": "2022-04-13715:19:14.4746056842", "UpdatedAt": "2022-04-13T15:19:14.4746086842",
"Spec": {
"Name": "back_config",
"Labels": {}
\end{verbatim}

**docker ps**
Чтобы просмотреть все контейнеры во всех состояниях, передайте аргумент - а. Docker автоматически настраивает локальный реестр образов на компьютере. Про- смотреть образы в реестре с помощью команды: docker images
Удалить образ из локального реестра Docker с помощью команды docker rmi. Указывается имя или ID образа, который требуется удалить. Допустим, удалим образ с именем temp-Ubuntu:version-1.0:
**docker rmi temp-Ubuntu:version-1.0**
Если образ используется контейнером, удалить его нельзя. Команда docker rmi возвращает сообщение об ошибке, в котором указывается контейнер, использующий
образ. Для удаления контейнера служит команда docker rm
\begin{verbatim}
docker rm happy_wilbur
\end{verbatim}
После удаления контейнера все данные В нем уничтожаются. При планировании хранения данных важно учитывать, что контейнеры являются временными.
Для перезапуска контейнера используется команда docker restart
\begin{verbatim}
docker restart happy_wilbur
\end{verbatim}
Так контейнер получает команду stop, а затем команду start.
Приостанавливает контейнер команда docker pause.
\begin{verbatim}
docker pause happy_wilbur
\end{verbatim}
Приостановка контейнера приводит к приостановке всех процессов. Эта команда позволяет контейнеру продолжить процессы в дальнейшем. Команда docker unpause отменяет приостановку всех процессов в указанных контейнерах.
**2.7 Флаги команды docker run**
Если перед флагом стоит два тире то это его полная форма, флаг с одним тире
- это сокращённый вариант некоего флага. Действуют они одинаково. Например, -р - это сокращённая форма флага рort:-1(--interactive) поток STDIN под- держивается в открытом состоянии даже если контейнер к STDIN не подключён; -t (--tty)-соединяет используемый терминал с потоками STDIN и STDOUT контей- нера.
Для того чтобы получить возможность взаимодействия с контейнером через тер- минал нужно совместно использовать флаги -i и -t.
**docker run -it tmp-ubuntu**
Запускает контейнер команда docker run. Для запуска контейнера из образа нужно просто указать его имя или идентификатор.
**docker run -d tmp-ubuntu**
Здесь для запуска контейнера в фоновом режиме следует добавить флаг -. -р (--port) порт это интерфейс, благодаря которому контейнер взаимодей- ствует с внешним миром. Например: конструкция 1000: 8000 перенаправляет порт Docker 8000 на порт 1000 компьютера, на котором выполняется контейнер. Если в контейнере работает некое приложение, способное выводить что-то в браузер, то, для того, чтобы к нему обратиться, в нашем случае можно перейти в браузере по адресу localhost:1000.
-d (--detach) запуск контейнер в фоновом режиме. Это позволяет использовать

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

**Основы безопасности в Docker**

5 основных правил:

1) Регулярно устанавливайте обновления

2) Ограничьте доступ к сокету службы Docker

3) Используйте непривилегированного пользователя внутри контейнера

4) Не запускайте контейнер с повышенными привилегиями

5) Используйте инструменты проверки docker-image на уязвимости

**Основы безопасности в Docker**
**Правило 1:** Регулярно устанавливайте обновления
Регулярные обновление хостовой машины и Docker позволят вам:
- Защититься от уязвимостей
Получать новый функционал
Продлевать поддержку производителя ПО
Быть в курсе имеющихся проблем у производителя Осваивать новые технологии
Помните, что контейнеры используют ядро совместно с хостом.
Эксплойт, запущенный внутри контейнера напрямую выполняются в ядре хоста.

**Правило 2:** Ограничьте доступ к сокету службы Docker
**Docker daemon** использует UNIX сокет /var/run/docker.sock для входящих соединений API. **Владельцем данного ресурса должен быть пользователь root.** И никак иначе. Изменение прав доступа к этому сокету по сути равносильно предоставлению root-доступа к хостовой системе.
Не используйте **Docker TCP** сокет без защиты (авторизации, шифрования):
***Expose daemon on tcp://localhost:2375 without TLS**
Exposing daemon on TCP without TLS helps legacy clients connect to the daemon. It also makes yourself vulnerable to remote code execution attacks. Use with caution.*

**Правило 3:** Настройка контейнера на
использование
непривилегированного
пользователя.
Это лучший способ избежать атаки на повышение привилегий.
Это можно сделать различными способами:

1. Используя флаг и команды docker run: 
**docker run -u 4000 alpine**

2. Во время сборки образа:

\begin{verbatim}
FROM alpine
**RUN groupadd-r myuser && useradd-r-g myuser myuser
<Здесь ещё можно выполнять команды от root-пользователя, например, ставить пакеты> 
USER myuser**
\end{verbatim}

3. Включить поддержку «user namespace» (пользовательского окружения) в Docker daemon: 

**Правило 4**  Избегайте запуска контейнеров с файлом - - privileged 
docker run - -privileged -p 127.0.0.1:3306:3306 —name mariadb 

**Правило 5:** Используйте инструменты проверки docker-image

на уязвимости

Используйте команду docker scan для сканирования образов:

Package manager: deb
project name: docker-image|mariadb
Docker image: mariadb
Platform: linux/amd64
Base image: ubuntu:20.04

Tested 185 dependencies for known vulnerabilities, found 19 vulnerabilities.

\section{Kubernetes}
Kubernetes (k8s)

**Kubernetes** работает по принципу «ведущий - ведомый».
Управление системой основано на двух подходах
**декларативном** - разработчик задает цели, а не пути их достижения, - которые система автоматически выбирает сама
**императивном** - разработчик может распоряжаться ресурсами с помощью команд «Создать», «Изменить», «Удалить>>

\subsection{Как работает Kubernetes}

**Kubectl** модуль **Kubernetes** для управления кластером (все - команды управления посылаются на **Master ноду**).
https://kubernetes.io/docs/tasks/tools/install-kubectl-windows

**Minikube** для создания **Kubernetes кластера Single-Node**, - оптимизированного для тестов и учебы (Master и Worker B одном).

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

\subsection{Возможности Kubernetes:}

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

Поднятие простого Kubernetes кластера на Windows

Minikube для создания Kubernetes кластера Single-Node, - оптимизированного для тестов и учебы (Master и Worker B одном).

\subsection{Кластер Kubernetes}

Компоненты кластера Kubernetes

\begin{figure}[H]
  \centering
  \includegraphics[width=12cm]{04-telematics-kub-cluster.png}
\end{figure}

\subsection{Nodes (ноды, узлы)}

Это физические или виртуальные машины. на которых развертываются и запускаются контейнеры с приложениями.
Совокупность Kubernetes нод образует кластер Kubernetes
Nodes бывают двух типов: 
**Master** (мастер-нода) - узел, управляющий
всем кластером.
**Worker** (рабочие ноды) - узлы, на которых работают контейнеры

\subsection{Pods (Поды)}
Pods - базовые модули управления приложениями состоящие из одного или нескольких контейнеров
Контейнеры в поде запускаются и работают вместе имеют общие сетевые ресурсы и хранилище
Под и все его контейнеры функционируют на одном узле и находятся там до завершения работы
Обычно Kubernetes сам создает поды

\begin{figure}[H]
  \centering
  \begin{subfigure}[b]{0.48\textwidth}
    \centering
    \includegraphics[width=\textwidth]{04-telematics-kub-pods.png}
  \end{subfigure}
  \hfill
  \begin{subfigure}[b]{0.48\textwidth}
    \centering
    \includegraphics[width=\textwidth]{04-telematics-kub-01.png}
    \caption{Компоненты master-ноды кластера Kubernetes}
  \end{subfigure}
\end{figure}

Поднятие простого Kubernetes кластера на Windows

Проще всего воспользоваться готовой реализацией - **Minikube**. Нам потребуется установить 3 приложения:
**VirtualBox
Kubectl
Minikube**
Другие модули **Kubernetes: kubeadm** (создание и настройка кластеров), **kubelet** (их запуск на хостах), **kubectl** (настройка компонентов, входящих в кластер - управление кластером).

Kubectl - модуль Kubernetes для управления кластером (все команды управления посылаются на Master ноду).
https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/

Далее в терминале запускаем кластер:
minikube start
"minikube ans Windows Home minikube start --no-vtx-check-cpusx-memory-gb-d-e-Ig

**Поднятие простого Kubernetes кластера на Windows**
Далее в терминале видим, если все прошло успешно:
**Done! kubectl is now configured to use "minikube"**
Конфигурационный файл **«config» kubectl расположен в:
\begin{verbatim}
C:\Users\User\.kube**
\end{verbatim}

Конфигурационный файл «config» kubectl расположен
\begin{verbatim}
C:\Users\User.kube
\end{verbatim}

Работа с Kubectl

Что такое Kubectl?
Kubectl - это инструмент командной строки для управления кластерами Kubernetes.
Kubectl ищет файл config в директории /.kube

Синтаксис Kubectl

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

**kubectl [command] [TYPE] [NAME] [flags]**

- command: определяет выполняемую операцию с одним или несколькими ресурсами, например, create, get, delete.
- TYPE: определяет тип ресурса.
- NAME: определяет имя ресурса.
- flags: определяет дополнительные флаги.

Простая инструкция по работе с k8s-кластером
Базовые команды по работе с k8s-кластером, используя утилиту rubectl:
**kubectl cluster-info** - информация о кластере
**kubectl get nodes** - получить все доступные ноды в кластере
**kubectl get pods** - получение списка развернутых подов
**kubectl run** - запуск пода на основе докер-образа (архаичный вариант запуска, обычно используются специально подготовленные манифесты в формате yaml).
**kubectl expose pod** - создание службы для межподового/межконтейнерного взаимодействия (архаичный вариант, обычно используются специально подготовленные манифесты в формате yaml)

**Поднятие простого Kubernetes кластера на Windows**

**Управление созданным Single-Node кластером**

**minikube start** - запуск кластера minikube

**minikube pause** - приостановка кластера minikube, не затрагивая развернутые приложения.

**minikube unpause** - возобновление работы приостановленного экземпляра

**minikube stop** - остановка.

**minikube delete** - удаление кластера minikube.

Работа внутри minikube: **minikube ssh**

Установка «Dashboard» - панели управления Kubernetes

**Установка «Dashboard» - панели управления Kubernetes**
**Dashboard** - панель управления Kubernetes

**Dashboard** - это веб-интерфейс пользователя Kubernetes.

**Dashboard** удобен для:

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

**Dashboard** также предоставляет информацию о состоянии ресурсов
**Kubernetes** в кластере и об возникших ошибках.

Dashboard - панель управления Kubernetes

Команды для установки на:

[https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/)

Интерактивное руководство - создание кластера Kubernetes

[https://kubernetes.io/docs/tutorials/kubernetes-basics/create-cluster/cluster-interactive/](https://kubernetes.io/docs/tutorials/kubernetes-basics/create-cluster/cluster-)

Интерактивное руководство - работа с кластером Docker Swarm

[https://labs.play-with-docker.com/](https://labs.play-with-docker.com/)

\section{git}

\end{document}
