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

Системное администрирование

Перевод Заметки о Unix история Unix до readline

21.02.2021 12:18:25 | Автор: admin
Unix и программы, работающие в этой ОС, существуют уже очень давно. В частности, библиотека GNU Readline появилась в 1989 году (как и Bash). Времени существования этой библиотеки (и подобных проектов) вполне достаточно для того чтобы она стала бы распространённым инструментов Unix-оболочек. В наши дни совершенно естественно воспринимать readline как нечто такое, что всегда было в Unix. Но, конечно, на самом деле это не так. Unix в её современном виде ведёт историю от V7 (1979) и 4.2. BSD (1983), поэтому множество Unix-дистрибутивов было разработано до появления readline. Это, в некоторой степени, сделало их такими, какими они были.



(Нельзя сказать, что GNU Readline и Bash были первоисточниками возможностей редактирования и автодополнения команд, да и прочего подобного в стиле readline. В Unix похожие методы работы восходят, как минимум, к 1983 году, к tcsh. Но оболочка tcsh, по разным причинам, не получила широкого распространения.)

Одним из очевидных последствий отсутствия readline было появление командной оболочки csh. Эта оболочка поддерживала множество инструментов для работы с историей команд. Их работа была основана на внедрение в командную строку особых строк. Обратимся к справке по csh из 4.2. BSD:

Механизмы подстановки из истории команд используют слова из ранее введённых команд в роли частей новых команд. Это упрощает повторение команд или аргументов ранее введённых команд в текущей команде. Благодаря этому упрощается и исправление опечаток в ранее введённых командах для этого приходится вводить меньше символов, к тому же, такой стиль работы даёт больший уровень уверенности в правильности исправленной команды. Работа системы подстановки из истории основана на использовании символа !, который может быть расположен в любом месте входного потока (при условии того, что не образуются вложенные конструкции).

Пожалуй, самой известной среди пользователей tcsh командой подстановки из истории является !!, которая повторяет предыдущую команду. В Bash есть похожий механизм, cf, и даже сегодня в руководстве по Bash есть указание на сходство cf с csh-версией соответствующего инструмента. Полагаю, что в наше время большинство тех, кто использует Bash, не применяет механизмы Bash для работы с историей команд, а просто прибегает к readline-инструментам, с которыми обычно проще работать.

(Это очевидное наблюдение, но с течением времени детали прошлого Unix различимы всё слабее, поэтому легко забыть о том, как далеко в прошлое уходит история некоторых из частей этой ОС. По крайней мере, для меня это именно так.)

P.S. У меня возникает такое ощущение, что широкая распространённость механизмов автодополнения команд и имён файлов понемногу влияет на то, какие имена команд и файлов применяют пользователи. Во времена, когда автодополнения не было, очень важным было то, чтобы имена команд и файлов были бы как можно короче. Неважно было то, что они могли быть очень похожи друг на друга, что могло бы привести к тому, что системе автозавершения ввода было бы сложно их различать. Как известно, короткие имена команд пользуются популярностью в Unix. Такие команды можно вводить быстрее, чем более длинные. В окружении V7 это имеет большое значение.

Пользуетесь ли вы tcsh?
Подробнее..

Bedrock Linux лего-набор для создания идеального linux-дистрибутива

22.02.2021 16:14:10 | Автор: admin


С момента появления Linux достаточно скоро возникло множество дистрибутивов: Slack, RedHat, Debian, SUSE и т. д. Тогда же возникла и проблема выбора дистрибутива, ведь каждый из них имеет свои особенности и преимущества, которые делают его особенным. RedHat и Debian наиболее стабильные и консервативные из дистрибутивов, Ubuntu заточен на удобство и имеет прекрасный пользовательский интерфейс, Gentoo свобода выбора и гибкость.

У каждого пользователя Linux были моменты, когда ему не хватало некоторых функций, реализованных в других дистрибутивах. Многим в свое время не понравилось, что Debian перешел на systemd и они создали на его основе новый дистрибутив Devuan. Некоторые перешли на Gentoo, где пользователь может создать среду с двумя системами инициализации: как с openrc, так и с systemd.

В разных дистрибутивах этот вопрос решается по-разному. Установка пакета, который отсутствует в штатном репозитории, решается с помощью docker-контейнеров, или использованием систем самодостаточных пакетов snap и flatpak. Можно даже ставить RPM пакеты на системах с пакетным менеджером DEB. В Gentoo имеется поддержка RPM и DEB пакетов. Все это работает, однако плохо масштабируется и не очень стабильно.

Создатели Bedrock Linux пошли дальше и создали полноценный мета-дистрибутив. В нем возможно использование не только пакетов, но и компонент различных Linux дистрибутивов, как кубиков Лего. В одном окружении можно создать систему из нескольких Linux OS, например установку дополнительных пакетов Ubuntu поверх базовых компонент Debian и Arch. Установочный скрипт доступен для следующих платформ.

  • aarch64;
  • armv7hl;
  • armv7l;
  • mips64el;
  • mips64;
  • mips;
  • mipsel;
  • ppc64;
  • ppc64le;
  • ppc;
  • s390;
  • x86_64;
  • x86;

Кстати, а почему установочный скрипт, а не полноценный установочный диск, или образ? Причина в том, что Bedrock Linux не имеет своего канонического дистрибутива, вместо этого имеется набор рецептов по сборке операционной системы из некоего набора ингредиентов. В этом Bedrock Linux похож на другой мета-дистрибутив Gentoo, однако в попытке объять необъятное продвинулся к самым границам здравомыслия, а возможно и перешел их.

Установка Bedrock и базовые команды


Используя уже установленный традиционный дистрибутив Linux с помощью установочного скрипта Bedrock трансформирует его в гибридную систему. Например, у вас уже установлена ОС Debian, с помощью установочного скрипта, вы получаете совмещенную среду с Ubuntu. Для начала надо запустить из под пользователя root.

sh ./bedrock-linux-<release>-<arch>.sh --hijack

Скрипт выдаст предупреждение, что это не учения.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **                                                               ** Continuing will:                                              ** - Move the existing install to a temporary location           ** - Install Bedrock Linux on the root of the filesystem         ** - Add the previous install as a new Bedrock Linux stratum     **                                                               ** YOU ARE ABOUT TO REPLACE YOUR EXISTING LINUX INSTALL WITH A   ** BEDROCK LINUX INSTALL! THIS IS NOT INTENDED TO BE REVERSIBLE! **                                                               ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *Please type "Not reversible!" without quotes at the prompt to continue:> Not reversible!__          __             __\ \_________\ \____________\ \___ \  _ \  _\ _  \  _\ __ \ __\   /  \___/\__/\__/ \_\ \___/\__/\_\_\          Bedrock Linux 0.7.19 Poki

Самое время ознакомиться с таблицей совместимости Linux дистрибутивов. Основные популярные дистрибутивы имеют хорошую степень поддержки, кроме возможно OpenSUSE. Для Linux Mint не поддерживается выгрузка и автоматическое установка. Не надо также забывать про таблицу совместимости компонент между собой. Бинарники, например, переносятся хорошо из одного дистрибутива в другой, а шрифты плохо.

Если все проверки прошли успешно, скрипт вносит необходимые изменения в ОС, после чего нужно перезагрузить компьютер, чтобы изменения вступили в силу. С этого момента пользователь находится в окружении Bedrock Linux. Теперь можно установить дополнительную ОС в контейнер, называемый stratum нечто наподобие chroot окружения, в котором проделаны специальные дыры для коммуникации с другими strata.
Однако прежде, чем начинать желательно ознакомиться с руководством по эксплуатации, вызвав brl tutorial basics. Простейшие команды Bedrock, назначение каждой очевидно.

# brl update# brl version# brl ctatus

Просмотр списка доступных дистрибутивов и установка.

# brl fetch --list# brl fetch alpine# brl fetch void


Как взаимодействуют дистрибутивы в составе Bedrock?


В определенных ситуациях можно выполнять команды из разных strata так, как будто они часть одной привычной Linux OS. Например команды из void и alpine можно использовать в одном конвейере. Первая команда устанавливает пакет jq на alpine, вторая jo на void. Конвейер читает из второй и передает на первую, все происходит прозрачно для пользователя.

$ sudo apk add jq$ sudo xbps-install -y jo$ jo "distro=bedrock" | jq ".distro"

Первоначальная ОС Debian Linux, над которой произвели действие --hijack теперь также является всего лишь stratum. О её существовании можно догадаться, выполнив некоторые из этих команд.

$ brl which lsdebian$ brl which /debian

Более определенно, вывод этих команд будет совпадать с содержимым файла /etc/os-release, который виден из текущего процесса shell. Это логично, так как каждый stratum видит лишь свой локальный файл, иначе параллельно установленные Debian и Ubuntu споткнулись бы о содержимое файла /etc/apt/sources.list.

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

$ brl which /bedrock/etc/bedrock.confglobal$ brl which /runglobal$ brl which /tmpglobal

Для тех случаев, когда процессам одного дистрибутива необходимо достучаться до локальных файлов другого, реализованы cross пути. Например чтобы из одной strata прочитать файл os-release другой нужно обращаться к ресурсам файловой системы используя путь /bedrock/strata/. Сам stratum bedrock служит лишь для cross чтения и записи файлов. Внутри crossfs файловая система FUSE, в которой запрашиваемые файлы перезаписываются на лету для обеспечения совместимости между различными strata.

$ brl which /bedrock/strata/bedrock/etc/os-release bedrock$ cat /bedrock/strata/bedrock/etc/os-releaseNAME="Bedrock Linux"ID=bedrockID_LIKE=bedrocklinuxVERSION="0.7.19 (Poki)"VERSION_ID="0.7.19"PRETTY_NAME="Bedrock Linux 0.7.19 Poki"HOME_URL="http://personeltest.ru/aways/bedrocklinux.org"$ brl which /bedrock/strata/my-alpine/etc/os-release my-alpine

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

$ strat void sh -c 'apk --help'

Обновление Bedrock


Bedrock обновляется незатейливо и просто Как и все дистрибутивы Linux, достаточно запустить brl update из под пользователя root. Это команда обновит лишь stratum Bedrock, остальные strata обновляются своими штатными средствами: например yum update, или dnf update для Redhat и CentOS.

Удаление strata


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

$ sudo brl disable alpine$ sudo brl remove alpine$ sudo remove -d void

Последняя команда совмещает, операции disable и remove.

Для чего действительно нужен Bedrock Linux?


В этот момент многие читатели скорее всего задаются вопросом: для чего нужно скрещивать ежа с ужом и создавать гибридные ОС, ведь не всегда рабочая станция Linux сама по себе бывает достаточно стабильной, особенно с закрытыми драйверами графической карты, или в сессии Wayland. Попробуем перечислить некоторые сценарии использования Bedrock Linux в практике.
  • Вы предпочитаете стабильные дистрибутивы Linux, такие как RedHat и Debian, однако вам также необходима поддержка нового железа: CPU, или недавно приобретенный принтер. Чтобы получить эту поддержку необходимо установить более свежую версия ядра и пакетов cups, hplips. Такая задача может быть решена единожды, но стабильная система с нестабильными пакетами уже не то,
  • Вам нравится дистрибутив, но не его система инициализации. Скажем, systemd вы предпочитаете openrc, или runit, однако хотели бы при этом использовать Ubuntu.
  • У вас есть задача вести разработку, или сопровождать программное обеспечение для Linux, однако ваш дистрибутив отличается от целевого. Например sh скрипты написанные для bash не будут корректно выполнены в Debian, так как в нем /bin/sh не является ссылкой на /bin/bash. Для таких сценариев в Bedrock Linux достаточно добавить stratum для Debian Linux.
  • Вы пытаетесь изменить ваши представления об использовании Linux OS. Впрочем это уже не имеет отношение к практике.


Подробнее..

Аудит событий Active Directory и других решений Microsoft в Quest Change Auditor анонс вебинара

22.02.2021 12:20:43 | Автор: admin
Change Auditor инструмент для автоматизации аудита изменений в AD, Azure AD, SQL Server, Exchange, Exchange Online, Sharepoint, Sharepoint Online, Windows File Server, OneDrive for Business, Skype for Business, VMware, NetApp, EMC, FluidFS. Есть предустановленные отчёты на различные виды угроз, а также на соответствие стандартам GDPR, SOX, PCI, HIPAA, FISMA, GLBA.

Change Auditor значительно снижает трудозатраты на аудит в сравнении с использованием встроенных средств аудита или PowerShell-скриптов. В ситуации, когда авторы систем аудита, основанных на скриптах, увольняются (а мы сталкивались с такой ситуацией у одного из заказчиков), наличие промышленной системы аудита играет новыми красками.

image

Приглашаем вас зарегистрироваться на вебинар, который состоится 24 февраля в 12 часов дня по московскому времени. Вы узнаете о возможностях решения, кейсах использования, лицензировании и сможете задать интересующие вопросы. Под катом ссылки на наши предыдущие статьи с описанием Change Auditor и других решений от Quest по информационной безопасности.


А кто это сделал? Автоматизируем аудит информационной безопасности

Что полезного можно вытащить из логов рабочей станции на базе ОС Windows

Управление доступом и формирование отчётов безопасности для окружения Microsoft в Quest Enterprise Reporter

Сравним инструменты для аудита изменений в Active Directory: Quest Change Auditor и Netwrix Auditor

Sysmon теперь может записывать содержимое буфера обмена

Включаем сбор событий о запуске подозрительных процессов в Windows и выявляем угрозы при помощи Quest InTrust

Как InTrust может помочь снизить частоту неудачных попыток авторизаций через RDP

Как снизить стоимость владения SIEM-системой и зачем нужен Central Log Management (CLM)

Выявляем атаку вируса-шифровальщика, получаем доступ к контроллеру домена и пробуем противостоять этим атакам

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

А ещё у нас есть:

Группа в Facebook

Канал в Youtube.
Подробнее..

AD Freeradius Google Autheticator. Установка с нуля для Cisco Anyconnect и не только

24.02.2021 20:16:16 | Автор: admin
Итак, у нас встала задача включить двухфакторную аутентификацию для Cisco AnyconnectVPN и некоторых других пакетов. Общими у всех задач есть одно они умеют аутентифицироваться в Radius.
Есть масса платных решений (например Cisco DUO ), но платное не значит лучше и зачем платить больше?

Да, критики скажут это очередная статья как натянуть сову на глобус или как подружить FreeRadius, MS Acitve Directory и Google Authenticator. Но есть нюансы, которые я хочу показать.

Во-первых. Мне нужно несколько типов аутентификации. Я это реализую нестандартными настройками FreeRadius и получу на трех разных портах одного сервера три типа аутентификации:
  1. ADlogin, ADPasswordGoogleAuth (логин из AD, паролем выступает склееная фраза из пароля в AD и цифр от GoogleAuth )
  2. ADlogin, ADPassword (стандартный вариант логина и пароля от AD, по сути чисто технический вариант, но нужен для Anyconnect)
  3. ADLogin, GoogleAuth ( логин из AD, пароль цифры GoogleAuth. Так сказать GoogleAuthenticator в чистом виде)

Во-вторых. Используя модуль shellinabox предоставляем возможность клиенту создать себе GoogleAuth токен самостоятельно, при этом не понижая уровня безопасности системы. Возможно не самое красивое решение но 100% работающее.

И в-третьих. Мне так и не удалось победить проблему: когда истекает время жизни пароля в AD, FreeRadius перестает считать его валидным и пробрасывает дальше ошибку. Т.е перестает предлагать сменить пароль в такой ситуации. Решение shellinabox позволяет решить эту проблему, предлагая пользователю в такой ситуации зайти на URL shellinabox.

Все проверено на Centos7 но без особых изменений зайдет на любом RedHat дистрибутиве и с непринципиальными модификациями на Ubuntu и FreeBSD. Другие дистрибуты не проверял, но общий смысл обязан сохранится.

1) Включаем NTP если не включено. Можно заменить любой аналогичной службой, важно чтоб время было синхронизировано корректно.

a) Установка
#yum install ntp


b) Включение на старте и сразу запуск
#systemctl enable now ntpd


c) Проверка
#ntpq p


2) Включаем Linux в AD. Я предпочитаю SSSD.

a) Установка
#yum install y sssd realmd oddjob oddjob-mkhomedir adcli samba-common samba-common-tools krb5-workstation openldap-clients policycoreutils-python

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

b) собственно ввод в домен
#realm join pbu.icb --user=имя-пользователя-домена


c) проверка
#realm list


Должно вывести нечто подобное:
my.domen
type: kerberos
realm-name: MY.DOMEN
domain-name: my.domen
configured: kerberos-member
server-software: active-directory
client-software: sssd
required-package: oddjob
required-package: oddjob-mkhomedir
required-package: sssd
required-package: adcli
required-package: samba-common-tools
login-formats: %U
login-policy: allow-permitted-logins
permitted-logins:


d) редактируем /etc/sssd/sssd.conf для ограничения по AD группам, которым можно ходить на эту машину. Читай аутентифицироваться в AD с этой машины.
use_fully_qualified_names = False
simple_allow_groups = GroupLinuxAdmins@my.domen, GroupUseVPN@my.domen
ad_gpo_ignore_unreadable = True


первая группа GroupLinuxAdmins@my.domen, члены которой могут администрировать систему, вторая GroupUseVPN@my.domen это те кто потом будет ходить в VPN.

e) Запускаем sssd
#chown root.root /etc/sssd/sssd.conf&&chmod 600 /etc/sssd/sssd.conf#systemctl restart sssd

Убеждаемся что sssd работает корректно:
#id  имя-пользователя-домена

Должно вывести список групп AD в которые входит пользователь домена имя-пользователя-домена

f) Разрешаем админам sudo
#echo "%GroupLinuxAdmins@my.domen ALL=(ALL) ALL" > /etc/sudoers.d/sudoadmin#chown root.root /etc/sudoers.d/sudoadmin&&chmod 600 /etc/sudoers.d/sudoadmin


g) Выключаем root для ssh, разрешаем ssh только членам группы GroupLinuxAdmins@my.domen.
Редактируем /etc/ssh/sshd_config, изменив или добавив строки ниже. ВАЖНО! Тут и дальше имена групп нужно использовать только в нижнем регистре.

PermitRootLogin no
AllowGroups grouplinuxadmins


И перезапускаем sshd
#systemctl restart sshd


3) Установка FreeRadius
a) Собственно установка
#yum -y install freeradius freeradius-utils#ln -s /etc/raddb/mods-available/pam /etc/raddb/mods-enabled/pam


b) Редактируем /etc/raddb/sites-enabled/default:
Находим в разделе authenticate строку вида
# pam

и убираем комментарий в начале строки ( символ # )

с) Собственно базовый радиус установлен. Только для localhost но уже можем проверять.
Парольное слово в Radius для localhost по-умолчанию: testing123

# radtest userVPN password_for_userVPN localhost 0 testing123


Правильный ответ будет если в конце ответа
Received Access-Accept


При неправильном пароле (тоже стоит обязательно проверить ):
В конце ответа будет
Received Access-Reject
и дальше
(0) -: Expected Access-Accept got Access-Reject


d) Дабавляем систему, которой можно обращаться к Radius, т.е устройство, которой будет организовывать Cisco AnyconnectVPN. У меня это Cisco Firepower. Пусть у него будет IP 10.10.10.5.
Добавляем в файл /etc/raddb/clients.conf

client ftd {
ipaddr = 10.10.10.5
secret = secretFTD
}


И включаем радиус со стартом
#systemctl enable --now radiusd


e) Редактируем /etc/raddb/radiusd.conf. данная настройка нужна для того, чтобы Google Authenticator мог проверить файл $HOME/.google_authenticator для всех пользователей.
находим
user = radiusd
group = radiusd

и меняем на
user = root
group = root


f) Собственно базовый Radius установлен. Если при установке FreeRadius что-то идет не так, очень полезная возможность консольной работы с FreeRadius. Для этого стопаем службу и запускаем Radius в консольном режиме с debug
#systemctl stop radius#radiusd -Xx


4) Ставим Google Autenticator
a) К сожелению я не знаю как подружить Google Authenticator и selinux. Поэтому отключаем.
Файл /etc/selinux/config меняем:
SELINUX=enforcing

на
SELINUX=permissive

После чего
#setenforce 0

а лучше вообще перезагрузить машину

b)
#yum install y epel-release#yum install y google-authenticator


5) Модифицируем FreeRadius для 3 типов аутентификации
a) Редактируем /etc/raddb/mods-enabled/pam, добавляя строки
pam radius11812{
pam_auth = radiusd_ad
}

pam radius21812{
pam_auth = radiusd_ga
}


b) В папке /etc/pam.d копируем pam настройки для разных типов аутентификации
Для просто в AD берем системную
#ln s /etc/pam.d/password-auth-ac /etc/pam.d/radiusd_ad

Для просто GoogleAuth пишем самостоятельно в /etc/pam.d/radiusd_ga

#%PAM-1.0
#
auth required pam_google_authenticator.so nullok
auth required pam_permit.so
account required pam_nologin.so
account include password-auth
password include password-auth
session include password-auth


!!! очень важный момент. При такой конфигурации если отсутствует привязка пользователя в профиле к GoogleAuth то такой пользователь считается валидным. Если нужно без ввода цифр GoogleAuth не пускать вообще, не зависимо от привязки, то нужно в первой строке убрать nullok а вторую строку убрать вообще.

c) Копируем /etc/raddb/sites-enabled/default для двух дополнительных портов
# cp /etc/raddb/sites-enabled/default /etc/raddb/sites-enabled/radius11812# cp /etc/raddb/sites-enabled/default /etc/raddb/sites-enabled/radius21812


d) Редактируем /etc/raddb/sites-enabled/radius11812
Находим в разделе authenticate строку вида
pam

и заменяем на
Auth-Type pam {
radius11812
}


e) Аналогично /etc/raddb/sites-enabled/radius21812
Находим в разделе authenticate строку вида
pam

и заменяем на
Auth-Type pam {
Radius21812
}


6) Устанавливаем shellinabox
a)
#yum install y shellinabox#yum enable now shellinabox


b) В принципе этого достаточно. Но некоторые любят красоту ;). Тогда дополнительно ставим еще figlet, и шрифт rebel.tlf ( взять с репозитория https://github.com/xero/figlet-fonts и положить в /usr/share/figlet ).

c) Добавляем вызов логики генерации GoogleAuth токена для всех пользователей
#echo . /usr/local/etc/radius_user_profiles.sh >> /etc/skel/.bash_profile


d) Создаем /usr/local/etc/radius_user_profiles.sh ( это вариант с украшательствами )
#!/bin/bash# Set groups for vpn, etc. ##   !!! Names of groups without caps letters !!!#VPNissuer="MyCompany"GROUP_VPN="groupusevpn"# Get the aliases and functionsif [ -f ~/.bashrc ]; then        . ~/.bashrcfi# User specific environment and startup programs# Make several commands available from user shell# for group VPN that use 2FA Google authenticatorif [[ -n $(id $USER | grep $GROUP_VPN) ]]  then     clear    [[ ! -d $HOME/bin ]] && mkdir $HOME/bin    [[ ! -f $HOME/bin/id ]] && ln -s /usr/bin/id $HOME/bin/id    [[ ! -f $HOME/bin/google-auth ]] && ln -s /usr/bin/google-authenticator $HOME/bin/google-auth    [[ ! -f $HOME/bin/grep ]] && ln -s /usr/bin/grep $HOME/bin/grep    [[ ! -f $HOME/bin/figlet ]] && ln -s /usr/bin/figlet $HOME/bin/figlet    [[ ! -f $HOME/bin/rebel.tlf ]] && ln -s /usr/share/figlet/rebel.tlf $HOME/bin/rebel.tlf    [[ ! -f $HOME/bin/sleep ]] && ln -s /usr/bin/sleep $HOME/bin/sleep  # Set PATH env to <home user directory>/bin    PATH=$HOME/bin    export PATH    if [[ ! -e $HOME/.google_authenticator ]]      then        figlet -t -c -f $HOME/bin/rebel.tlf "Welcome to $VPNissuer GAuth setup portal"        sleep 1.5        echo "Please, run Google Autheticator to setup OTP and prepare to scan QR code.If you don't have, please download that from market:AppStore    - https://apps.apple.com/us/app/google-authenticator/id388497605Play Market - https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en"        sleep 1.5        google-auth -f -t -w 3 -r 3 -R 30 -d -e 1 -l "$VPNissuer" -i "$USER"        echo "Congratulations, now you can use an OTP token from application as a password to VPN."        logout    else        echo "You have already setup a Google Authenticator        "        logout    fifi

e) Устнавливаем разрешения на выполнение всем.
#chmod 755  /usr/local/etc/radius_user_profiles.sh


f) Можно файлы типа .google_authenticator вынести в отдельный каталог ( по-умолчанию это файлы $HOME/.google_authenticator). Увеличивает ли это безопасность системы? Нет, а удобство дело привычки. Для этого надо сделать несколько шагов:
  • в скрипте /usr/local/etc/radius_user_profiles.sh заменить строки
    if [[! -e $HOME/.google_authenticator ]]
    google-auth -f -t -w 3 -r 3 -R 30 -d -e 1 -l "$VPNissuer" -i "$USER"

    на
    if [[! -e /path_secrets/${USER} ]]
    google-auth -f -t -w 3 -r 3 -R 30 -d -e 1 -l "$VPNissuer" -i "$USER" --secret=/path_secrets/$USER
  • и в модулях PAM /etc/pam.d/radiusd и /etc/pam.d/radiusd_ga
    везде после pam_google_authenticator.so добавить параметр secret=/path_secrets/${USER}
    auth required pam_google_authenticator.so secret=/path_secrets/${USER} nullok
  • создать каталог
    #mkdir /path_secrets#chmod 777 /path_secrets
    

7) Теперь самое интересное. Shellinabox это по-сути графическая web оболочка для шелла. Для того чтоб не нарушить безопасность системы делаем отдельный sshd c ограничением по группе AD на нестандартном порту и направляем shelinabox на этот порт. Стандартный 22 остается для администраторов и снаружи недоступен.

a) Копируем systemd service скрипт и конфиг sshd:
#cp /usr/lib/systemd/system/sshd.service /usr/lib/systemd/system/sshd_web.service#cp /etc/ssh/sshd/sshd_config /etc/ssh/sshd_web_config


b) Редактируем /usr/lib/systemd/system/sshd_web.service заменяя строку
ExecStart=/usr/sbin/sshd -D $OPTIONS

на
ExecStart=/usr/sbin/sshd -D -f /etc/ssh/sshd_web_config $OPTIONS


c) Редактируем /etc/ssh/sshd_web_config добавляя или исправляя параметры:
port 2022
MaxAuthTries 3
MaxSessions 1
AllowGroups groupusevpn


Таким образом мы запускаем дополнительный шелл sshd на порту 2022 не открывая его на firewall т.к обращения к нему исключительно по интерфейсу local.

d) Редактируем /etc/sysconfig/shellinaboxd изменив параметр на
OPTS=" -s /:SSH:localhost:2022"


e) В папке /var/lib/shellinabox по умолчанию лежат самосгенеренные и самоподписанные сертификаты shellinabox. Лично у себя я установил дополнительно nginx в который внес реальные сертификаты ssl, вынеся shellinabox на порт 8443 ( любой нестандартный )

#yum install y nginx


Конфигурация для nginx:

server {
listen 443 ssl;
server_name shellinabox.my.domen;

add_header Strict-Transport-Security max-age=15768000; includeSubDomains always;

set $upstream localhost:8443;

proxy_intercept_errors on;
underscores_in_headers on;

location ~ ^/(.*) {
proxy_pass $upstream$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/ privkey.pem;
ssl_protocols TLSv1.2;
ssl_dhparam /etc/ssl/ssl-dhparams.pem;
}

и в /etc/sysconfig/shellinaboxd меняем
PORT=8443


f) Перезапускаем после всех изменений.
#systemctl daemon-reload#systemctl enable now sshd_web#systemctl enable now shellinabox

Если ставили nginx то
#systemctl enable now nginx


g) Открываем порты firewalld
firewall-cmd --new-zone=radius permanentfirewall-cmd --zone=radius --add-source=10.10.10.5 --permanentfirewall-cmd --zone=radius --add-port=1812/udp --permanentfirewall-cmd --zone=radius --add-port=11812/udp --permanentfirewall-cmd --zone=radius --add-port=21812/udp --permanentfirewall-cmd --reload


8) Тестируем весь конструктор.
a) Заходим на shellinabox.my.domen
b) Логинимся пользователем VPN и получаем QR-код для GoogleAuth
c) Ставим на смартфон GoogleAuthenticator и сканим им QR-код.
d)
#radtest userVPN password_for_userVPNXXXXXX localhost 0 testing123

где XXXXXX цифры с GoogleAuthenticator. Результат должен быть Received Access-Accept
e)
#radtest userVPN password_for_userVPN localhost:11812 0 testing123

Результат должен быть Received Access-Accept
f)
#radtest userVPN XXXXXX localhost:21812 0 testing123 

где XXXXXX цифры с GoogleAuthenticator. Результат должен быть Received Access-Accept

9) Собственно VPN
a) Если все предидущие этапы прошли успешно то прописываем сервер типа Radius c IP и портом 11812/UDP как первый фактор в CISCO AnyconnectVPN и его же с портом 21812/UDP как второй фактор.





b) Деплоим конфигурацию и проверяем.

Как понятно из процесса тестирования, те системы, которые не умеют отдельно спрашивать первый и второй фактор ( или мы не хотим факторы разделять специально) мы направляем на порт Radius 1812 и используем схему пароль_ADXXXXXX добавляя цифры с Google Authenticator сразу после пароля без пробела.

Незакрытые вопросы:
  • Смена пароля при истечении времени жизни пароля через FreeRadius. Буду благодарен за советы.
  • SELINUX и GoogleAuthenticator.
  • Хотелось бы более красивого, аккуратного и, главное, более управляемого варианта генерации GoogleAuth токена, чем банальный шелл-скрипт.


PS. В статье использовались материалы http://personeltest.ru/aways/habr.com/ru/post/516362, откуда взята идея shellinabox
Подробнее..

Fortinet Single Sign-On. Описание технологии

25.02.2021 08:12:25 | Автор: admin

Приветствуем! На протяжении всего времени нашей работы с решениями компании Fortinet, а в частности с межсетевым экраном нового поколения FortiGate, одним из самых интересующих вопросов является контроль и отслеживание трафика отдельных пользователей или групп пользователей. Сегодня мы хотим подробно рассказать о механизме прозрачной аутентификации пользователей на межсетевом экране FortiGate с помощью технологии Fortinet Single Sign-On. Данная статья будет посвящена именно теоретическому аспекту FSSO, поскольку в данном случае без теории тяжело разобраться, что происходит на практике.

Single Sign-On (SSO) - механизм, позволяющий идентифицированным пользователям получать доступ к различным ресурсам в сети без повторной аутентификации. При работе с межсетевым экраном FortiGate, SSO реализуется с помощью FSSO (Fortinet Single Sign On) - комплекса программных агентов, который позволяет устройству FortiGate идентифицировать пользователей сети и тем самым контролировать их доступ к ресурсам сети, а также отслеживать трафик различных пользователей. Когда пользователь аутентифицируется в домене, FSSO агент отправляет на FortiGate имя пользователя, его IP адрес, а также список групп, к которым данный пользователь принадлежит. FortiGate использует данную информацию для того, чтобы разрешить или запретить данному пользователю доступ к сетевым ресурсам. FSSO обычно используется со службами каталогов, такими как Windows Active Directory или Novell eDirectory. Работа FSSO зависит от используемой службы каталогов. В данной статье мы будем рассматривать FSSO для Windows Active Directory (AD).

FSSO для Windows AD использует коллектор агента. Агенты для контроллеров домена (DC агент) также могут использоваться, в зависимости от режима работы коллектор агента. Существует два основных режима работы: DC Agent Mode (режим, в котором используются DC агент) и Polling Mode (в этом режиме используются только коллектор агенты). Также на FortiGate может использоваться Polling режим, который не требует установки сторонних агентов на сервера. Однако, данный вариант подходит только для простых сетей с минимальным количеством пользователей.

Для начала рассмотрим режим DC Agent Mode. Данный режим является рекомендованным для FSSO. Для него требуется:

DC агент, установленный на каждый контроллер домена - если в сети имеется несколько контроллеров домена, агент должен быть установлен на каждый из них;

Коллектор агент - второй компонент FSSO, установленный на сервер Windows, являющийся членом домена. Он собирает события, полученные с агентов для контроллеров домена, и перенаправляет их на FortiGate. Также он отвечает за верификацию групп и проверку рабочих станций на предмет выхода пользователя из системы. Коллектор агент может отсылать на FortiGate информацию о локальных группах безопасности, организационных подразделениях, а также о глобальных группах безопасности. Также коллектор агент можно настроить для выполнения DNS запросов.

Схема работы FSSO в режиме DC Agent Mode представлена на рисунке ниже:

  1. При аутентификации пользователя DC агент перехватывает запись о входе на контроллере домена.

  2. Затем DC агент выполняет DNS запрос для определения IP адреса пользователя и передает полученную информацию на коллектор.. После того, как коллектор получает информацию, он снова выполняет DNS запрос для того, чтобы определить, был ли изменен IP адрес пользователя.

  3. После этого, вся информация о пользователе передается на FortiGate.

  4. После того, как коллектор передал всю информацию о пользователе, FortiGate знает этого пользователя, его IP адрес и группы, к которым он принадлежит. Когда пользователь пытается получить доступ к интересующим его сетевым ресурсам (в том числе и к Интернету), FortiGate сравнивает IP адрес источника с IP адресами, находящимися в списке активных FSSO пользователей. Поскольку пользователь уже авторизован в домене, и FortiGate содержит информацию о нем, пользователь не будет авторизовываться повторно. Вместо этого, доступ данного пользователя к интересующему ресурсу будет разрешен или запрещен в зависимости от политики безопасности, под которую попадает трафик данного пользователя.

Перейдем ко второму режиму - Collector Agent-Based Polling Mode. Данный режим не требует установки DC агентов на контроллеры домена. Однако, требования к установке коллектор агентов на сервер или сервера, принадлежащие домену, остаются. В таком случае коллектор агент периодически опрашивает контроллеры домена на предмет наличия событий log-on пользователей. Для этого могут использоваться различные методы:

NetAPI: Агент обращается к временным сессиям, созданным на контроллере домена в момент входа пользователей в домен, и вызывает функцию NetSessionEnum. Данный метод работает быстрее остальных, однако он может пропустить некоторые события входа при высокой нагрузке контроллера домена. Это связано с тем, что при высокой нагрузке сессии могут удаляться из оперативной памяти до того, как агент успеет к ним обратиться и передать информацию на FortiGate.

WinSecLog: Агент обращается ко всем логам событий безопасности в контроллере домена. В таком случае, он не пропустит ни одного события входа пользователя, поскольку логи событий безопасности обычно не удаляются. Однако, при передаче информации на FortiGate возможны задержки - главными причинами являются большой объем сети, а также медленная скорость записи логов. Данный метод является самым распространенным.

WMI: Агент с помощью Windows API получает системную информацию с контроллера домена. Контроллер домена по запросу возвращает все требуемые события входа пользователей в домен. Данный способ позволяет уменьшить нагрузку канала между коллектор агентом и контроллером домена.

Схема работы Collector Agent-Based Polling режима представлена на рисунке ниже:

  1. Пользователь аутентифицируется в домене, предоставляя свои учетные данные на контроллер домена;

  2. Коллектор агент периодически (раз в несколько секунд) опрашивает контроллер домена на предмет наличия событий входа пользователей в домен;

  3. Коллектор агент посылает полученную информацию на FortiGate;

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

И третий режим, который мы сегодня рассмотрим - Agentless Polling Mode. Процесс его работы схож с предыдущим режимом, однако вместо использования коллектор агента, FortiGate опрашивает контроллер домена самостоятельно. Из-за этого присутствует ряд ограничений:

  • Требуется больше системных ресурсов;

  • Происходит опрос только двух событий - ID 4768 и ID 4769. Для этого используется протокол SMB;

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

Схема работы данного режима представлена на рисунке ниже.

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

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

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

Подведем итоги, выделив основные отличия в режимах DC Agent Mode и Polling Mode:

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

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

Также, в режиме DC Agent Mode необходимые события собираются один раз и отправляются на привязанные коллектор агенты. Поэтому, события входа пользователей не упускаются. А в режиме Polling Mode, некоторые события входа могут быть пропущены, или при их передаче может возникнуть задержка.

Для удобства, основные отличия в режимах были сведены в таблицу:

DC Agent Mode

Polling Mode

Инсталяция

Сложная - одна инсталяция на один контроллер домена. Требуется перезагрузка.

Простая - одна инсталляция или настройка на FortiGate

Требуется ли DC агент

Да

Нет

Масштабирование

Высокий уровень масштабирования

Низкий уровень масштабирования

Уровень захвата событий

Захватываются все события

Некоторые события могут быть пропущены (NetAPI) или могут быть переданы с задержкой (WinSecLog)

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

Youtube канал

Группа Вконтакте

Яндекс Дзен

Наш сайт

Телеграм канал

Подробнее..

Перевод CICD обещания и реальность

24.02.2021 14:21:40 | Автор: admin


Мы говорим CI/CD и подразумеваем непрерывную интеграцию. Никто не имеет в виду (и не практикует) непрерывный деплоймент. Вообще никогда. О нем все забыли. Пора это изменить.


Поучительная история


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


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


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


Мораль истории такова: устраняйте не симптомы, а причину.


Что подводит нас к разговору о CI/CD?


CI/CD (непрерывная интеграция и доставка, или деплоймент) это часть нашей жизни. Мы ходим на конференции по CI/CD, пишем статьи о CI/CD, ведем блоги о CI/CD, указываем CI/CD на странице LinkedIn. Никто даже не спорит, надо оно нам или нет. Мы все одинаково обожаем CI/CD. Так ведь?


Вот только мы говорим CI/CD и подразумеваем непрерывную интеграцию. Никто не имеет в виду (и не практикует) непрерывный деплоймент. О нем все забыли.


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


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


Что это вообще такое CI/CD?


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


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


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


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


Гибельный водоворот разработки


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


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


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


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


Раз все имеющиеся разработчики заняты, нужно нанять много новых и потратить еще больше усилий на их координацию. Скоро вам понадобятся отдельные должности SRE, Ops, QA, билд-инженер, чтобы героически бороться с каждым симптомом по отдельности. Для этой оравы нужно будет больше менеджеров и так далее. Вуаля! Получаем огромную, дорогую и неповоротливую компанию.


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


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


Каким должен быть интервал? В идеале 15 минут. Максимум час. Предсказуемость важна не меньше продолжительности, поэтому человек тут будет только мешать. Если сейчас вам требуется 15 дней, а не минут, не отчаивайтесь. Любые усилия по сокращению интервала обязательно окупятся. Любые!


Вижу, вы сомневаетесь. Моя команда, мол, такое не осилит, здесь вам не Facebook и не Google.


Вы идете сложным путем


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


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


Как это вообще можно сравнивать? Пока код еще свеж в памяти, мы четко видим проблему и ее решение.


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


В таком ритме разработчики обычно находят больше 80% всех багов сразу пока ничего еще не забылось и знаешь, на что смотреть. Если что-то пошло не так, можно тут же слепить еще один диф.


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


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


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


Задача номер 1 для технических руководителей в 2021 году


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


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


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


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


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


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


Не надо быть гением, чтобы раскрыть весь потенциал CI/CD. Честное слово. Надо просто приложить чуть больше усилий к тому, чтобы наладить этот процесс. Хорошие специалисты вырастают в хороших командах.


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


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


Сложно ли это? Еще как. Надеюсь, мне удалось вас убедить, что оно того стоит. Это изменит вашу жизнь. Это шаг к социотехническим системам будущего. Чем больше команд его сделают, тем лучше. А какой у вас план по CI/CD на 2021 год?


Узнать больше о CI/CD и получить практику создания пайплайнов можно на курсе Слёрма CI/CD на примере Gitlab CI.
Подробнее..

Свидетели DevOps мифы и байки про девопсов и тех, кто их нанимает

25.02.2021 10:21:06 | Автор: admin

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

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

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

Трудности перевода

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

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

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

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

Байка про хромого девопса

Недавно нас позвали на помощь в один проект, где стояла, на первый взгляд, простая задача. Web-приложение работало через web-сокеты, но было развернуто внутри периметра, а на фронте стоял ISPManager, который в качестве reverse proxy использовал apache. Юный девопс, работавший в этом проекте, перепробовал все примеры конфига апача, которые нашел в Гугле, и вконец разочаровавшись в его поисковых способностях, перешел уже было к Яндексу, но тут менеджер проекта забил тревогу. На задачу к тому моменту было потрачено 72 часа. 72 часа, Карл! Кто вам сказал, что методология DevOps ускоряет разработку и сокращает time-to-market? ;)

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

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

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

Про технологии

DevOps это про культуру и философию совместной работы, но с этим понятием также сопряжен определенный технологический стек. Скорее всего я не ошибусь, если скажу, что какие-нибудь NetApp, Cisco, AIX или MS SQL воспринимаются как старый добрый олдскул (хотя это не совсем так, и классические вендоры делают гигантские шаги в новом направлении), а вот, скажем, Docker, Ansible, Jenkins и Prometheus в нашем сознании прочно ассоциируются с DevOps, SRE и новыми веяниями.

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

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

И отдельная боль это сеть. В сети надо разбираться, владеть инструментами диагностики. Сеть не зависит от платформы, она есть везде и напрямую (а порой больно) влияет на работоспособность и производительность всего остального. Когда человек, грезящий себя девопсом, наивно полагает, что надо установить свежую версию Kibana, потому что она умеет конвертировать адреса IPv6 в IPv4 это звучит как анекдот. Но потом он, например, берет и орудует с сетью вот так:

или вот так:

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

А давайте-ка все распилим на микросервисы, засунем в Docker и запустим в Kubernetes

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

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

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

Вот, кстати, символичный фрагмент одного из скриптов по деплою:

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

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

А про кубер вспоминается недавно гулявший ролик, где старый фильм озвучили новыми словами:

- А у вас есть kubernetes?

- Да, конечно, ну как у всех! Как полагается.

- А зачем?

- Ну как это зачем? Это же

Дальше следует немая сцена, гримаса ужаса и спустя некоторое время человек, вероятно, идет топиться.

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

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

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

Просто через docker run:

docker run

docker run -d \

-e 'ALERTMANAGER_URL=http://alertmanager:9093' \

-e 'BOLT_PATH=/data/bot.db' \

-e 'STORE=bolt' \

-e 'TELEGRAM_ADMIN=1234567' \

-e 'TELEGRAM_TOKEN=XXX' \

-v '/srv/monitoring/alertmanager-bot:/data' \

--name alertmanager-bot \

metalmatze/alertmanager-bot:0.4.3

С помощью docker-compose

docker-compose

networks:

alertmanager-bot: {}

services:

alertmanager-bot:

command:

- --alertmanager.url=http://localhost:9093

- --log.level=info

- --store=bolt

- --bolt.path=/data/bot.db

environment:

TELEGRAM_ADMIN: "1234"

TELEGRAM_TOKEN: XXXXXXX

image: metalmatze/alertmanager-bot:0.4.3

networks:

- alertmanager-bot

ports:

- 8080:8080

restart: always

volumes:

- ./data:/data

version: "3"

А вот тот же сервис в Kubernetes

кубер

apiVersion: v1

items:

- apiVersion: v1

data:

admin: MTIzNA==

token: WFhYWFhYWA==

kind: Secret

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

type: Opaque

- apiVersion: v1

kind: Service

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

ports:

- name: http

port: 8080

targetPort: 8080

selector:

app.kubernetes.io/name: alertmanager-bot

- apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

podManagementPolicy: OrderedReady

replicas: 1

selector:

matchLabels:

app.kubernetes.io/name: alertmanager-bot

serviceName: alertmanager-bot

template:

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

containers:

- args:

- --alertmanager.url=http://localhost:9093

- --log.level=info

- --store=bolt

- --bolt.path=/data/bot.db

env:

- name: TELEGRAM_ADMIN

valueFrom:

secretKeyRef:

key: admin

name: alertmanager-bot

- name: TELEGRAM_TOKEN

valueFrom:

secretKeyRef:

key: token

name: alertmanager-bot

image: metalmatze/alertmanager-bot:0.4.3

imagePullPolicy: IfNotPresent

name: alertmanager-bot

ports:

- containerPort: 8080

name: http

resources:

limits:

cpu: 100m

memory: 128Mi

requests:

cpu: 25m

memory: 64Mi

volumeMounts:

- mountPath: /data

name: data

restartPolicy: Always

volumes:

- name: data

persistentVolumeClaim:

claimName: data

volumeClaimTemplates:

- apiVersion: v1

kind: PersistentVolumeClaim

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 1Gi

storageClassName: standard

kind: List

Если решение все же принято, вам предстоит перелопатить горы документации, написать тонны yaml-a, мучительно искать, где пропущен отступ, по 10 раз пересобирать контейнеры. И в этом момент вы еще и не знаете, что через пару недель пройдете новый круг ада, подстраивая ваш деплоймент под Pod Security Policy и разные энтерпрайзные фичи. Конечно, когда вы это дотащите до конца, вы получите красивый сервис, который легко скейлится, автоматически перезапускается при сбоях, который можно обновлять, используя, например, канареечные релизы или какой-нибудь blue-green deployment.

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

Автоматизация как истинный путь джедая

Наши бэкапшики помнят один случай, как сотрудник заказчика собирался в консоли что-то удалить то ли ненужный симлинк, то ли копию конфига. А его то и дело дергали. По воле случая в один момент так сошлось, что товарищ успел набрать rm -rf /oradata, работая от рута, потом чихнул, что в свою очередь пробудило в его организме рута позывы на исход жидкости, а по дороге обратно он зацепился языками с товарищами. Когда он вернулся на рабочее месте, его экран спал. Не будучи в силах терпеть проделки этого вечно дремлющего устройства и дабы преподнести ему урок бодрости, товарищ решительно разбудил его точным ударом в Enter. В общем, когда все делаешь руками, нелепые вещи случаются сплошь и рядом.

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

Самое плохое в автоматизации это время, которое надо на нее потратить. И самое хорошее в ней тоже время, которое она впоследствие высвобождает. Например, пару лет назад нам потребовалось в нашем облаке IaaS развернуть инфраструктуру под нового e-commerce заказчика. Архитектура проекта: кластер БД, пул серверов приложений, распределенное хранилище, слой кэширования, сетевые балансировщики, WAF, ну и стандартная обвязка в виде телеметрии, СРК и сбора логов с визуализацией. Конечно, виртуальные машины мы давно создавали при помощи terraform, благо под наше облако можно использовать AWS-провайдер, так как мы по API совместимы. Программные компоненты и раньше ставили через ansible, и опыт настройки всего по отдельности, в общем, был. Но мы задались целью описать инфраструктуру проекта в виде единого пайплайна. На это ушло время, ну и до сих пор части этой автоматизации совершенствуются, так как еще много где были нами после переиспользованы.

Когда нам позже подвернулся аналогичный проект, различия описывались на уровне файла ответов. Мы развернули проект за 2 дня, причем большую часть времени занял перенос данных. В Gitlab CI запускался pipeline, который заполнял переменные для terraform, который затем запускался runner-ом. Тот создавал в облаке сети, диски и ВМ. ВМ запускались с cloud-init, который ставил внутрь puppet agent, который после старта связывался с foreman, забирал настройки для своей роли и деплоил все ПО. Через service discovery подключался мониторинг всех служб, везде встал и настроился filebeat, а бакап полился в S3. Voila! Все быстро и четко, без ошибок и ручных тестов на каждом шаге.

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

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

  • осмысленный сайзинг ресурсов;

  • отдельные точки монтирования (отдельный диск/раздел) под данные приложений и все, что может быстро пухнуть;

  • синхронизацию времени по ntp;

  • переход на использование ключей вместо паролей в ssh;

  • настроить ротацию всех логов;

  • иметь автоматический механизм обновления протухающих SSL-сертификатов

  • покрыть мониторингом все ключевые показатели жизнеспособности системы и не забыть про алерты;

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

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

Эти простые меры по принципу Парето составляют не более 20% действий по первичной настройке, но дают 80% вклада в стабильную и автономную их работу в будущем.

Если у вас уже есть provision-система, то следом можно подключить инструмент IaC, и накатывать все эти настройки всегда по умолчанию, через какой-нибудь базовый профиль. Я в такой профиль еще включаю набор обязательных утилит, чтобы, к примеру, в экстренной ситуации не оказалось, что в системе нет lsof, tcpdump и т. п.

Время и внимание хорошего девопса такие проблемы не отнимают, потому что он их еще в самом начале решил.

Как не стать героем баек

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

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

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

И напоследок завет работодателям

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

Если вам понадобился девопс, у вас вероятно уже есть разработка. Задачи, которые выполняет девопс это та же разработка, только инфраструктуры и процессов, поэтому к ней в целом применимы те же правила. Над девопсом должен быть senior или тимлид, который через систему контроля версий делает code review, проверяет и одобряет PR/MR. И совершенно точно не стоит доверять архитектурные вопросы человеку без подтвержденного архитектурного опыта. Лучше поищите стороннюю экспертизу для подстраховки.

Мне также нравится концепция, когда отдельно от специалистов DevOps позиционируется еще одна команда - платформенных инженеров (Platform engineer). Она не работает непосредственно с девелоперами, но именно она снабжает девопса готовыми, отлаженными рычагами к этой платформе и уже настроенному инструментарию. Именно такой подход позволяет снизить планку требований к девопсу, позволяя ему спокойнее учиться и снижая риск его ошибок.

В этом месте ставлю не точку, а многоточие, так как тема неисчерпаемая и весьма холиварная. Комментарии, как говорится, покажут :)

Подробнее..

Перевод Как Apache Kafka поддерживает 200К партиций в кластере?

02.03.2021 04:06:51 | Автор: admin


В Kafka топик может содержать множество партиций, между которыми распределяются записи. Партиции это единицы параллелизма. В целом, чем больше партиций, тем выше пропускная способность. Однако есть некоторые факторы, которые стоит учитывать, когда в кластере Kafka много партиций. Рад сообщить, что в Apache Kafka, начиная с версии 1.1.0, было существенно увеличено количество партиций, которые может поддерживать один кластер Kafka с точки зрения деплоймента и доступности.


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


Брокер Kafka по умолчанию выполняет контролируемое отключение, чтобы минимизировать сбои в обслуживании клиентов. Контролируемое отключение проходит следующие этапы. (1) Сигнал SIG_TERM отправляется брокеру для завершения работы. (2) Брокер отправляет запрос контроллеру, уведомляя, что он готов к отключению. (3) Контроллер затем меняет лидеров партиций на этом брокере на других брокеров и сохраняет эту информацию в ZooKeeper. (4) Контроллер отправляет информацию о новых лидерах другим брокерам в кластере. (5) Контроллер отправляет выключающемуся брокеру положительный ответ на запрос, и брокер, наконец, завершает свой процесс. Таким образом это никак не влияет на клиентов, потому что их трафик уже перенаправлен на других брокеров. Этот процесс изображен на Рисунке 1. Заметьте, что шаги (4) и (5) могут происходить параллельно.



Рис. 1. (1) Инициация отключения на брокере 1; (2) брокер 1 отправляет запрос о контролируемом отключении контроллеру на брокере 0; (3) контроллер записывает новых лидеров в ZooKeeper; (4) контроллер отправляет информацию о новых лидерах брокеру 2; (5) контроллер отправляет положительный ответ брокеру 1.


До версии Kafka 1.1.0 во время контролируемого отключения контроллер перемещает лидеров по одной партиции за раз. Для каждой партиции контроллер выбирает нового лидера, параллельно записывает его в ZooKeeper и отправляет нового лидера другим брокерам через удаленный запрос. В этом процессе есть несколько недостатков. Во-первых, у синхронной записи в ZooKeeper более высокое время задержки, что замедляет процесс контролируемого отключения. Во-вторых, отправка нового лидера по партиции за раз добавляет много маленьких удаленных запросов к каждому брокеру, что может вызвать задержку обработки новых лидеров.


Начиная с Kafka 1.1.0 и далее контролируемое отключение происходит значительно быстрее. Во-первых, при записи в ZooKeeper используется асинхронный API. Вместо того чтобы записывать лидера для одной партиции, ждать, пока этот процесс завершится, а потом записывать следующего, контроллер асинхронно размещает лидеров для многих партиций в ZooKeeper, а потом ждет завершения процесса. Это позволяет обрабатывать запросы на пайплайне между брокером Kafka и сервером ZooKeeper и снижает общее время задержки. Во-вторых, информация о новых лидерах отправляется батчами. Вместо одного удаленного запроса для каждой партиции контроллер отправляет один удаленный запрос с лидером от всех затронутых партиций.


Время обработки отказа контроллером также было значительно улучшено. Если случается отказ контроллера, кластер Kafka автоматически выбирает контроллером другого брокера. Прежде чем иметь возможность выбрать лидеров партиций свеженазначенный контроллер должен загрузить состояние всех партиций в кластере из ZooKeeper. Если произошел серьезный сбой контроллера, окно недоступности партиции может длиться столько, сколько продолжается срок действия сессии ZooKeeper, плюс время перезагрузки состояния контроллера. Поэтому сокращение времени перезагрузки состояния улучшает доступность в таком редком случаем. До версии 1.1.0 в Kafka для перезагрузки используется синхронный API ZooKeeper. Начиная с версии 1.1.0 это также заменено на асинхронный API для сокращения времени задержки.


Мы провели тесты для оценки улучшений по времени контролируемого отключения и перезагрузки контроллера. Для обоих тестов мы загрузили набор из пяти узлов ZooKeeper на выделенных серверах.


Для первого теста мы подготовили кластер Kafka с пятью брокерами на отдельных серверах. В этом кластере мы создали 25 000 топиков, в каждом топике по одной партиции и две реплики, в общем получив 50 000 партиций. Таким образом на каждом брокере было 10 000 партиций. Затем мы замерили время, которое понадобилось для контролируемого отключения. Результаты представлены в таблице ниже.


Версия Kafka 1.0.0 Kafka 1.1.0
Время контролируемого отключения 6,5 минут 3 секунды

Большую часть улучшений дает исправление затрат на журналирование, при котором проводятся ненужные записи для каждой партиции в кластере при смене лидера одной партиции. Просто исправив затраты на журналирование, мы снизили время контролируемого отключения с 6,5 минут до 30 секунд. Переход на асинхронный API ZooKeeper снизил это время до 3 секунд. Эти улучшения существенно снизили время, необходимое для перезагрузки кластера Kafka.


Для второго теста мы подготовили другой кластер Kafka, состоящий из пяти брокеров, создали 2 000 топиков, в каждом по 50 партиций и одной реплике. В сумме во всем кластере получилось 100 000 партиций. Затем мы замерили время перезагрузки состояния контроллера и увидели 100% улучшение (время перезагрузки снизилось с 28 секунд в Kafka 1.0.0 до 14 секунда в Kafka 1.1.0).


Учитывая эти изменения, на поддержку какого количества партиций вы можете рассчитывать в Kafka? Точное число зависит от таких факторов как допустимое окно недоступности, время задержки ZooKeeper, тип хранения на брокере и т.д. В качестве общего правила мы рекомендуем иметь на каждом брокере до 4 000 партиций и до 200 000 партиций в кластере. Основная причина для лимита на кластере заключается в том, что нужно подстраховаться на тот редкий случай серьезного сбоя контроллера, о котором мы писали выше. Обратите внимание, что другие соображения, связанные с партициями, также применимы, и вам может потребоваться дополнительная настройка конфигурации с большим количеством партиций.


Более подробную информацию вы найдете в KAFKA-5642 и KAFKA-5027.


От редакции: Команда Слёрма готовит подробный видеокурс по Apache Kafka. Спикеры Анатолий Солдатов из Авито и Александр Миронов из Stripe. Вводные уроки уже доступны в личном кабинете. Релиз полной версии курса апрель 2021. Подробности.

Подробнее..

Рефакторинг пет проекта докеризация, метрики, тесты

17.02.2021 20:19:33 | Автор: admin

Всем привет, я php разработчик. Я хочу поделиться историей, как я рефакторил один из своих телеграм ботов, который из поделки на коленке стал сервисом с более чем 1000 пользователей в очень узкой и специфической аудитории.

Предыстория

Пару лет назад я решил тряхнуть стариной и поиграть в LineAge II на одном из популярных пиратских серверов. В этой игре есть один игровой процесс, в котором требуется "поговорить" с ящиками после смерти 4 боссов. Ящик стоит после смерти 2 минуты. Сами боссы после смерти появляются спустя 24 +/- 6ч, то есть шанс появится есть как через 18ч, так и через 30ч. У меня на тот момент была фуллтайм работа, да и в целом не было времени ждать эти ящики. Но нескольким моим персонажам требовалось пройти этот квест, поэтому я решил "автоматизировать" этот процесс. На сайте сервера есть RSS фид в формет XML, где публикуются события с серверов, включая события смерти босса.

Задумка была следующей:

  • получить данные с RSS

  • сравнить данные с локальной копией в базе данных

  • если есть разница данных - сообщить об этом в телеграм канал

  • отдельно сообщать если босса не убили за первые 9ч сообщением "осталось 3ч", и "осталось 1,5ч". Допустим вечером пришло сообщение, что осталось 3ч, значит смерть босса будет до того, как я пойду спать.

Код на php был написан быстро и в итоге у меня было 3 php файла. Один был с god object классом, а другие два запускали программу в двух режимах - парсер новых, или проверка есть ли боссы на максимальном "респе". Запускал я их крон командами. Это работало и решало мою проблему.

Другие игроки замечали, что я появляюсь в игре сразу после смерти боссов, и через 10 дней у меня на канале было около 50 подписчиков. Так же попросили сделать такое же для второго сервера этого пиратского сервиса. Задачу я тоже решил копипастой. В итоге у меня уже 4 файла с почти одинаковым кодом, и файл с god object. Потом меня попросили сделать то же самое для третьего сервера этого пиратского сервиса. И это отлично работало полтора года.

В итоге у меня спустя полтора года:

  • у меня 6 файлов, дублируют себя почти полностью (по 2 файла на сервер)

  • один god object на несколько сотен строк

  • MySQL и Redis на сервере, где разместил код

  • cron задачи, которые запускают файлы

  • ~1400 подписчиков на канале в телеграм

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

Ожидаемый результат после рефакторинга

  1. Отрефакторить код так, чтобы легче было вносить изменения. Важный момент - отрефакторить без изменения бизнес логики, по сути раскидать god object по файлам, сам код не править, иначе это затянет сроки. Следовать PSR-12.

  2. Докеризировать воркера для удобства переноса на другой сервер и прозрачность запуска и остановки

  3. Запускать воркера через supervisor

  4. Внедрить процесс тестирования кода, настроить Codeception

  5. Докеризировать MySQL и Redis

  6. Настроить Github Actions для запуска тестов и проверки на code style

  7. Поднять Prometheus, Grafana для метрик и мониторинга работоспособности

  8. Сделать докер контейнер, который будет отдавать метрики на страницу /metrics для Prometheus

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

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

Шаг 1. Рефакторинг приложения

Одним из требований было не потратить на это недели, поэтому основные классы я решил сделать наследниками Singleton

<?phpdeclare(strict_types=1);namespace AsteriosBot\Core\Support;use AsteriosBot\Core\Exception\DeserializeException;use AsteriosBot\Core\Exception\SerializeException;class Singleton{    protected static $instances = [];    /**     * Singleton constructor.     */    protected function __construct()    {        // do nothing    }    /**     * Disable clone object.     */    protected function __clone()    {        // do nothing    }    /**     * Disable serialize object.     *     * @throws SerializeException     */    public function __sleep()    {        throw new SerializeException("Cannot serialize singleton");    }    /**     * Disable deserialize object.     *     * @throws DeserializeException     */    public function __wakeup()    {        throw new DeserializeException("Cannot deserialize singleton");    }    /**     * @return static     */    public static function getInstance(): Singleton    {        $subclass = static::class;        if (!isset(self::$instances[$subclass])) {            self::$instances[$subclass] = new static();        }        return self::$instances[$subclass];    }}

Таким образом вызов любого класса, который от него наследуются, можно делать методом getInstance()

Вот так, например, выглядел класс подключения к базе данных

<?phpdeclare(strict_types=1);namespace AsteriosBot\Core\Connection;use AsteriosBot\Core\App;use AsteriosBot\Core\Support\Config;use AsteriosBot\Core\Support\Singleton;use FaaPz\PDO\Database as DB;class Database extends Singleton{    /**     * @var DB     */    protected DB $connection;    /**     * @var Config     */    protected Config $config;    /**     * Database constructor.     */    protected function __construct()    {        $this->config = App::getInstance()->getConfig();        $dto = $this->config->getDatabaseDTO();        $this->connection = new DB($dto->getDsn(), $dto->getUser(), $dto->getPassword());    }    /**     * @return DB     */    public function getConnection(): DB    {        return $this->connection;    }}

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

Шаг 2: Докеризация воркеров

Запуск всех контейнеров я сделал через docker-compose.yml

Конфиг сервиса для воркеров выглядит так:

  worker:    build:      context: .      dockerfile: docker/worker/Dockerfile    container_name: 'asterios-bot-worker'    restart: always    volumes:      - .:/app/    networks:      - tier

А сам docker/worker/Dockerfile выглядит так:

FROM php:7.4.3-alpine3.11# Copy the application codeCOPY . /appRUN apk update && apk add --no-cache \    build-base shadow vim curl supervisor \    php7 \    php7-fpm \    php7-common \    php7-pdo \    php7-pdo_mysql \    php7-mysqli \    php7-mcrypt \    php7-mbstring \    php7-xml \    php7-simplexml \    php7-openssl \    php7-json \    php7-phar \    php7-zip \    php7-gd \    php7-dom \    php7-session \    php7-zlib \    php7-redis \    php7-session# Add and Enable PHP-PDO ExtenstionsRUN docker-php-ext-install pdo pdo_mysqlRUN docker-php-ext-enable pdo_mysql# RedisRUN apk add --no-cache pcre-dev $PHPIZE_DEPS \        && pecl install redis \        && docker-php-ext-enable redis.so# Install PHP ComposerRUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer# Remove CacheRUN rm -rf /var/cache/apk/*# setup supervisorADD docker/supervisor/asterios.conf /etc/supervisor/conf.d/asterios.confADD docker/supervisor/supervisord.conf /etc/supervisord.confVOLUME ["/app"]WORKDIR /appRUN composer installCMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

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

Шаг 3: Настройка supervisor

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

Код файла worker.php

<?phprequire __DIR__ . '/vendor/autoload.php';use AsteriosBot\Channel\Checker;use AsteriosBot\Channel\Parser;use AsteriosBot\Core\App;use AsteriosBot\Core\Connection\Log;$app = App::getInstance();$checker = new Checker();$parser = new Parser();$servers = $app->getConfig()->getEnableServers();$logger = Log::getInstance()->getLogger();$expectedTime = time() + 60; // +1 min in seconds$oneSecond = time();while (true) {    $now = time();    if ($now >= $oneSecond) {        $oneSecond = $now + 1;        try {            foreach ($servers as $server) {                $parser->execute($server);                $checker->execute($server);            }        } catch (\Throwable $e) {            $logger->error($e->getMessage(), $e->getTrace());        }    }    if ($expectedTime < $now) {        die(0);    }}

У RSS есть защита от спама, поэтому пришлось сделать проверку на секунды и посылать не более 1го запроса в секунду. Таким образом мой воркер каждую секунду выполняет 2 действия, сначала проверяет rss, а затем калькулирует время боссов для сообщений о старте или окончании времени респауна боссов. После 1 минуты работы воркер умирает, и его перезапускает supervisor

Сам конфиг supervisor выглядит так:

[program:worker]command = php /app/worker.phpstderr_logfile=/app/logs/supervisor/worker.lognumprocs = 1user = rootstartsecs = 3startretries = 10exitcodes = 0,2stopsignal = SIGINTreloadsignal = SIGHUPstopwaitsecs = 10autostart = trueautorestart = truestdout_logfile = /dev/stdoutstdout_logfile_maxbytes = 0redirect_stderr = true

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

[supervisord]nodaemon=true[include]files = /etc/supervisor/conf.d/*.conf

Набор полезных команд supervisorctl:

supervisorctl status       # статус воркеровsupervisorctl stop all     # остановить все воркераsupervisorctl start all    # запустить все воркераsupervisorctl start worker # запустить один воркера с конфига, блок [program:worker]

Шаг 4: Настройка Codeception

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

# Codeception Test Suite Configuration## Suite for unit or integration tests.actor: UnitTestermodules:    enabled:        - Asserts        - \Helper\Unit        - Db:              dsn: 'mysql:host=mysql;port=3306;dbname=test_db;'              user: 'root'              password: 'password'              dump: 'tests/_data/dump.sql'              populate: true              cleanup: true              reconnect: true              waitlock: 10              initial_queries:                - 'CREATE DATABASE IF NOT EXISTS test_db;'                - 'USE test_db;'                - 'SET NAMES utf8;'    step_decorators: ~

Шаг 5: Докеризация MySQL и Redis

На сервере, где работало это приложение, у меня было еще пара других ботов. Все они использовали один сервер MySQL и один Redis для кеша. Я решил вынести все, что связано с окружением в отельный docker-compose.yml, а самих ботов залинковать через внешний docker network

Выглядит это так:

version: '3'services:  mysql:    image: mysql:5.7.22    container_name: 'telegram-bots-mysql'    restart: always    ports:      - "3306:3306"    environment:      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"      MYSQL_ROOT_HOST: '%'    volumes:      - ./docker/sql/dump.sql:/docker-entrypoint-initdb.d/dump.sql    networks:      - tier  redis:    container_name: 'telegram-bots-redis'    image: redis:3.2    restart: always    ports:      - "127.0.0.1:6379:6379/tcp"    networks:      - tier  pma:    image: phpmyadmin/phpmyadmin    container_name: 'telegram-bots-pma'    environment:      PMA_HOST: mysql      PMA_PORT: 3306      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"    ports:      - '8006:80'    networks:      - tiernetworks:  tier:    external:      name: telegram-bots-network

DB_PASSWORD я храню в .env файле, а ./docker/sql/dump.sql у меня лежит бекап для инициализации базы данных. Так же я добавил external network так же, как в этом конфиге - в каждом docker-compose.yml каждого бота на сервере. Таким образом они все находятся в одной сети и могут использовать общие базу данных и редис.

Шаг 6: Настройка Github Actions

В шаге 4 этого туториала я добавил тестовый фреймфорк Codeception, который для тестирования требует базу данных. В самом проекте нет базы, в шаге 5 я ее вынес отдельно и залинковал через external docker network. Для запуска тестов в Github Actions я решил полностью собрать все необходимое на лету так же через docker-compose.

name: Actionson:  pull_request:    branches: [master]  push:    branches: [master]jobs:  build:    runs-on: ubuntu-latest    steps:      - name: Checkout        uses: actions/checkout@v2      - name: Get Composer Cache Directory        id: composer-cache        run: |          echo "::set-output name=dir::$(composer config cache-files-dir)"      - uses: actions/cache@v1        with:          path: ${{ steps.composer-cache.outputs.dir }}          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}          restore-keys: |            ${{ runner.os }}-composer-      - name: Composer validate        run: composer validate      - name: Composer Install        run: composer install --dev --no-interaction --no-ansi --prefer-dist --no-suggest --ignore-platform-reqs      - name: PHPCS check        run: php vendor/bin/phpcs --standard=psr12 app/ -n      - name: Create env file        run: |          cp .env.github.actions .env      - name: Build the docker-compose stack        run: docker-compose -f docker-compose.github.actions.yml -p asterios-tests up -d      - name: Sleep        uses: jakejarvis/wait-action@master        with:          time: '30s'      - name: Run test suite        run: docker-compose -f docker-compose.github.actions.yml -p asterios-tests exec -T php vendor/bin/codecept run unit

Инструкция onуправляет когда билд триггернётся. В моем случае - при создании пулл реквеста или при коммите в мастер.

Инструкция uses: actions/checkout@v2 запускает проверку доступа процесса к репозиторию.

Далее идет проверка кеша композера, и установка пакетов, если в кеше не найдено

Затем в строке run: php vendor/bin/phpcs --standard=psr12 app/ -nя запускаю проверку кода соответствию стандарту PSR-12 в папке ./app

Так как тут у меня специфическое окружение, я подготовил файл .env.github.actionsкоторый копируется в .env Cодержимое .env.github.actions

SERVICE_ROLE=testTG_API=XXXXXTG_ADMIN_ID=123TG_NAME=AsteriosRBbotDB_HOST=mysqlDB_NAME=rootDB_PORT=3306DB_CHARSET=utf8DB_USERNAME=rootDB_PASSWORD=passwordLOG_PATH=./logs/DB_NAME_TEST=test_dbREDIS_HOST=redisREDIS_PORT=6379REDIS_DB=0SILENT_MODE=trueFILLER_MODE=true

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

Затем я собираю проект при помощи docker-compose.github.actions.ymlв котором прописано все необходимое для тестирвания, контейнер с проектом и база данных. Содержимое docker-compose.github.actions.yml:

version: '3'services:  php:    build:      context: .      dockerfile: docker/php/Dockerfile    container_name: 'asterios-tests-php'    volumes:      - .:/app/    networks:      - asterios-tests-network  mysql:    image: mysql:5.7.22    container_name: 'asterios-tests-mysql'    restart: always    ports:      - "3306:3306"    environment:      MYSQL_DATABASE: asterios      MYSQL_ROOT_PASSWORD: password    volumes:      - ./tests/_data/dump.sql:/docker-entrypoint-initdb.d/dump.sql    networks:      - asterios-tests-network##  redis:#    container_name: 'asterios-tests-redis'#    image: redis:3.2#    ports:#      - "127.0.0.1:6379:6379/tcp"#    networks:#      - asterios-tests-networknetworks:  asterios-tests-network:    driver: bridge

Я закомментировал контейнер с Redis, но оставил возможность использовать его в будущем. Сборка с кастомным docker-compose файлом, а затем тесты - запускается так

docker-compose -f docker-compose.github.actions.yml -p asterios-tests up -ddocker-compose -f docker-compose.github.actions.yml -p asterios-tests exec -T php vendor/bin/codecept run unit

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

Шаг 7: Настройка Prometheus и Grafana

В шаге 5 я вынес MySQL и Redis в отдельный docker-compose.yml. Так как Prometheus и Grafana тоже общие для всех моих телеграм ботов, я их добавил туда же. Сам конфиг этих контейнеров выглядит так:

  prometheus:    image: prom/prometheus:v2.0.0    command:      - '--config.file=/etc/prometheus/prometheus.yml'    restart: always    ports:      - 9090:9090    volumes:      - ./prometheus.yml:/etc/prometheus/prometheus.yml    networks:      - tier  grafana:    container_name: 'telegram-bots-grafana'    image: grafana/grafana:7.1.1    ports:      - 3000:3000    environment:      - GF_RENDERING_SERVER_URL=http://renderer:8081/render      - GF_RENDERING_CALLBACK_URL=http://grafana:3000/      - GF_LOG_FILTERS=rendering:debug    volumes:      - ./grafana.ini:/etc/grafana/grafana.ini      - grafanadata:/var/lib/grafana    networks:      - tier    restart: always  renderer:    image: grafana/grafana-image-renderer:latest    container_name: 'telegram-bots-grafana-renderer'    restart: always    ports:      - 8081    networks:      - tier

Они так же залинкованы одной сетью, которая потом линкуется с external docker network.

Prometheus: я прокидываю свой конфиг prometheus.yml, где я могу указать источники для парсинга метрик

Grafana: я создаю volume, где будут храниться конфиги и установленные плагины. Так же я прокидываю ссылку на сервис рендеринга графиков, который мне понадобиться для отправки alert. С этим плагином alert приходит со скриншотом графика.

Поднимаю проект и устанавливаю плагин, затем перезапускаю Grafana контейнер

docker-compose up -ddocker-compose exec grafana grafana-cli plugins install grafana-image-rendererdocker-compose stop  grafana docker-compose up -d grafana

Шаг 8: Публикация метрик приложения

Для сбора и публикации метрик я использовал endclothing/prometheus_client_php

Так выглядит мой класс для метрик

<?phpdeclare(strict_types=1);namespace AsteriosBot\Core\Connection;use AsteriosBot\Core\App;use AsteriosBot\Core\Support\Singleton;use Prometheus\CollectorRegistry;use Prometheus\Exception\MetricsRegistrationException;use Prometheus\Storage\Redis;class Metrics extends Singleton{    private const METRIC_HEALTH_CHECK_PREFIX = 'healthcheck_';    /**     * @var CollectorRegistry     */    private $registry;    protected function __construct()    {        $dto = App::getInstance()->getConfig()->getRedisDTO();        Redis::setDefaultOptions(            [                'host' => $dto->getHost(),                'port' => $dto->getPort(),                'database' => $dto->getDatabase(),                'password' => null,                'timeout' => 0.1, // in seconds                'read_timeout' => '10', // in seconds                'persistent_connections' => false            ]        );        $this->registry = CollectorRegistry::getDefault();    }    /**     * @return CollectorRegistry     */    public function getRegistry(): CollectorRegistry    {        return $this->registry;    }    /**     * @param string $metricName     *     * @throws MetricsRegistrationException     */    public function increaseMetric(string $metricName): void    {        $counter = $this->registry->getOrRegisterCounter('asterios_bot', $metricName, 'it increases');        $counter->incBy(1, []);    }    /**     * @param string $serverName     *     * @throws MetricsRegistrationException     */    public function increaseHealthCheck(string $serverName): void    {        $prefix = App::getInstance()->getConfig()->isTestServer() ? 'test_' : '';        $this->increaseMetric($prefix . self::METRIC_HEALTH_CHECK_PREFIX . $serverName);    }}

Для проверки работоспособности парсера мне нужно сохранить метрику в Redis после получения данных с RSS. Если данные получены, значит все нормально, и можно сохранить метрику

        if ($counter) {            $this->metrics->increaseHealthCheck($serverName);        }

Где переменная $counter это количество записей в RSS. Там будет 0, если получить данные не удалось, и значит метрика не будет сохранена. Это потом понадобится для alert по работе сервиса.

Затем нужно метрики опубликовать на странице /metric чтобы Prometheus их спарсил. Добавим хост в конфиг prometheus.yml из шага 7.

# my global configglobal:  scrape_interval:     5s # Set the scrape interval to every 15 seconds. Default is every 1 minute.  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.  # scrape_timeout is set to the global default (10s).scrape_configs:  - job_name: 'bots-env'    static_configs:      - targets:          - prometheus:9090          - pushgateway:9091          - grafana:3000          - metrics:80 # тут будут мои метрики по uri /metrics

Код, который вытащит метрики из Redis и создаст страницу в текстовом формате. Эту страничку будет парсить Prometheus

$metrics = Metrics::getInstance();$renderer = new RenderTextFormat();$result = $renderer->render($metrics->getRegistry()->getMetricFamilySamples());header('Content-type: ' . RenderTextFormat::MIME_TYPE);echo $result;

Теперь настроим сам дашборд и alert. В настройках Grafana сначала укажите свой Prometheus как основной источник данных, а так же я добавил основной канал нотификации Телеграм (там добавляете токен своего бота и свой chat_id с этим ботом)

Настройка GrafanaНастройка Grafana
  1. Метрика increase(asterios_bot_healthcheck_x3[1m]) Показывает на сколько метрика asterios_bot_healthcheck_x3 увеличилась за 1 минуту

  2. Название метрики (будет под графиком)

  3. Название для легенды в пункте 4.

  4. Легенда справа из пункта 3.

  1. Правило, по которому проверяется метрика. В моем случае проверяет что за последние 30 секунд проблем не было

  2. Правило, по которому будет срабатывать alert. В моем случае "Когда сумма из метрики А между сейчас и 10 секунд назад"

  3. Если нет данных вообще - слать alert

  4. Сообщение в alert

Выглядит alert в телеграм так (помните мы настраивали рендеринг картинок для alert?)

Alert в ТелеграмAlert в Телеграм
  1. Обратите внимание, alert заметил падение, но все восстановилось. Grafana приготовилась слать alert, но передумала. Это то самое правило 30 секунд

  2. Тут уже все упало больше чем на 30 секунд и alert был отправлен

  3. Сообщение, которое мы указали в настройках alert

  4. Ссылка на dashboard

  5. Источник метрики

Шаг 9: Телеграм бот

Настройка телеграм бота ничем не отличается от настройки воркера. Телеграм бот по сути у меня это еще один воркер, я запустил его при помощи добавления настроек в supervisor. Тут уже рефакторинг проекта дал свои плоды, запуск бота был быстрым и простым.

Итоги

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

Ссылки на проекты

Подробнее..

Перевод Создание пайплайнов CI с помощью Tekton (внутри Kubernetes). Часть 12

20.02.2021 10:19:11 | Автор: admin

В этой статье мы собираемся создать пайплайн непрерывной интеграции (CI) с Tekton, фреймворком с открытым исходным кодом для создания конвейеров CI / CD в Kubernetes.


Мы собираемся подготовить локальный кластер Kubernetes через kind и установить на нем Tekton. После этого мы создадим пайплайн, состоящий из двух шагов, который будет запускать модульные тесты приложения, создавать образ Docker и отправлять его в DockerHub.


Это 1 из 2 частей, в которой мы установим Tekton и создадим задачу, запускающую тест нашего приложения. Вторая часть доступна здесь.


Создание кластера k8s


Мы используем kind для создания кластера Kubernetes для нашей установки Tekton:


$ kind create cluster --name tekton

Установка Tekton


Мы можем установить Tekton, применив файл release.yaml из последней версии репозитория tektoncd/pipeline на GitHub:


$ kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.20.1/release.yaml

Это установит Tekton в пространство имен tekton-pipelines. Мы можем проверить успешность установки, указав модули в этом пространстве имен и убедившись, что они находятся в состоянии выполнения.


$ kubectl get pods --namespace tekton-pipelinesNAME                                           READY   STATUS    RESTARTS   AGEtekton-pipelines-controller-74848c44df-m42gf   1/1     Running   0          20stekton-pipelines-webhook-6f764dc8bf-zq44s      1/1     Running   0          19s

Настройка Tekton CLI


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


Мы можем установить его через Homebrew:


$ brew tap tektoncd/tools$ brew install tektoncd/tools/tektoncd-cli$ tkn versionClient version: 0.16.0Pipeline version: v0.20.1

Концепции


Tekton предоставляет пользовательские определения ресурсов (CRD) для Kubernetes, которые можно использовать для определения наших пайплайнов. В этом руководстве мы будем использовать следующие настраиваемые ресурсы:


  • Задача: серия шагов, которые выполняют команды (в CircleCI это называется Job).


  • Пайплайн: набор задач (в CircleCI это называется рабочим процессом Workflow)


  • PipelineResource: ввод или вывод Pipeline (например, репозиторий git или файл tar)



Мы будем использовать следующие два ресурса для определения выполнения наших задач и пайплайна:


  • TaskRun: определяет выполнение задачи
  • PipelineRun: определяет выполнение пайплайна

Например, если мы пишем задачу и хотим ее протестировать, мы можем выполнить ее с помощью TaskRun. То же самое относится и к пайплайну: для выполнения конвейера нам нужно создать PipelineRun.


Код приложения


В нашем примере Pipeline мы собираемся использовать приложение Go, которое просто выводит сумму двух целых чисел. Вы можете найти код приложения, тест и Dockerfile в каталоге src/ этого репо.


Создание нашей первой задачи


Наша первая задача будет запускать тесты приложения внутри клонированного репозитория git. Создайте файл 01-task-test.yaml со следующим содержимым:


apiVersion: tekton.dev/v1beta1kind: Taskmetadata:  name: testspec:  resources:    inputs:      - name: repo        type: git  steps:    - name: run-test      image: golang:1.14-alpine      workingDir: /workspace/repo/src      command: ["go"]      args: ["test"]

Блок resources: определяет входные данные, необходимые нашей задаче для выполнения своих шагов. Нашему шагу (названному run-test) требуется клонированный репозиторий git с примером tekton в качестве входных данных, и мы можем создать эти входные данные с помощью PipelineResource.


Создайте файл с названием 02-pipelineresource.yaml:


apiVersion: tekton.dev/v1alpha1kind: PipelineResourcemetadata:  name: arthurk-tekton-examplespec:  type: git  params:    - name: url      value: https://github.com/arthurk/tekton-example    - name: revision      value: master

Тип ресурса git будет использовать git для клонирования репозитория в каталог /workspace/$input_name при каждом запуске задачи. Поскольку наш ввод называется repo, код будет клонирован в /workspace/repo. Если бы наш ввод был назван foobar, он был бы клонирован в /workspace/foobar.


Следующий блок в нашей задаче (steps:) определяет команду для выполнения и образ Docker, в котором следует выполнить эту команду. Мы собираемся использовать образ golang Docker, так как Go уже установлен.


Для запуска команды go test нам нужно сменить каталог. По умолчанию команда запускается в каталоге /workspace/repo, но в нашем репозитории с примером tekton приложение Go находится в каталоге src. Мы делаем это, установив рабочий каталог: /workspace/repo/src.


Затем мы указываем команду для запуска (go test), но обратите внимание, что команда (go) и args (test) должны быть определены отдельно в файле YAML.


Примените Task и PipelineResource с помощью kubectl:


$ kubectl apply -f 01-task-test.yamltask.tekton.dev/test created$ kubectl apply -f 02-pipelineresource.yamlpipelineresource.tekton.dev/arthurk-tekton-example created

Выполняем нашу задачу


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


Создайте файл 03-taskrun.yaml со следующим содержимым:


apiVersion: tekton.dev/v1beta1kind: TaskRunmetadata:  name: testrunspec:  taskRef:    name: test  resources:    inputs:      - name: repo        resourceRef:          name: arthurk-tekton-example

Это примет нашу задачу (taskRef это ссылка на нашу ранее созданную задачу с именем test) с нашим репозиторием git tekton-example в качестве входных данных (resourceRef это ссылка на наш PipelineResource с именем arthurk-tekton-example) и выполнит ее.


Примените файл с помощью kubectl, а затем проверьте ресурсы Pods и TaskRun. Pod пройдет через статус Init:0/2 и PodInitializing, а затем успешно:


$ kubectl apply -f 03-taskrun.yamlpipelineresource.tekton.dev/arthurk-tekton-example created$ kubectl get podsNAME                READY   STATUS      RESTARTS   AGEtestrun-pod-pds5z   0/2     Completed   0          4m27s$ kubectl get taskrunNAME      SUCCEEDED   REASON      STARTTIME   COMPLETIONTIMEtestrun   True        Succeeded   70s         57s

Чтобы увидеть вывод контейнеров, мы можем запустить следующую команду. Обязательно замените testrun-pod-pds5z на имя модуля из выходных данных выше (оно будет отличаться для каждого запуска).


$ kubectl logs testrun-pod-pds5z --all-containers{"level":"info","ts":1588477119.3692405,"caller":"git/git.go:136","msg":"Successfully cloned https://github.com/arthurk/tekton-example @ 301aeaa8f7fa6ec01218ba6c5ddf9095b24d5d98 (grafted, HEAD, origin/master) in path /workspace/repo"}{"level":"info","ts":1588477119.4230678,"caller":"git/git.go:177","msg":"Successfully initialized and updated submodules in path /workspace/repo"}PASSok      _/workspace/repo/src    0.003s

Наши тесты прошли, и наша задача была выполнена. Затем мы воспользуемся Tekton CLI, чтобы увидеть, как мы можем упростить весь этот процесс.


Использование Tekton CLI для запуска задачи


Tekton CLI обеспечивает более быстрый и удобный способ запуска задач.


Вместо того, чтобы вручную писать манифест TaskRun, мы можем запустить следующую команду, которая берет нашу задачу (с именем test), генерирует TaskRun (со случайным именем) и отображает ее журналы:


$ tkn task start test --inputresource repo=arthurk-tekton-example --showlogTaskrun started: test-run-8t46mWaiting for logs to be available...[git-source-arthurk-tekton-example-dqjfb] {"level":"info","ts":1588477372.740875,"caller":"git/git.go:136","msg":"Successfully cloned https://github.com/arthurk/tekton-example @ 301aeaa8f7fa6ec01218ba6c5ddf9095b24d5d98 (grafted, HEAD, origin/master) in path /workspace/repo"}[git-source-arthurk-tekton-example-dqjfb] {"level":"info","ts":1588477372.7954974,"caller":"git/git.go:177","msg":"Successfully initialized and updated submodules in path /workspace/repo"}[run-test] PASS[run-test] ok   _/workspace/repo/src    0.006s

Вывод


Мы успешно установили Tekton в локальном кластере Kubernetes, определили задачу и протестировали ее, создав TaskRun через манифест YAML, а также через Tekton CLI tkn.


Весь пример кода доступен здесь.


В следующей части мы собираемся создать задачу, которая будет использовать Kaniko для создания образа Docker для нашего приложения, а затем будет отправлять его в DockerHub. Затем мы создадим пайплайн, который последовательно будет запускать обе наши задачи (запускать тесты приложения, сборку и отправку).


Часть 2 доступна здесь.

Подробнее..

Ломаем и чиним etcd-кластер

01.03.2021 20:22:05 | Автор: admin

etcd это быстрая, надёжная и устойчивая к сбоям key-value база данных. Она лежит в основе Kubernetes и является неотъемлемой частью его control-plane. Именно поэтому критически важно уметь бэкапить и восстанавливать работоспособность как отдельных нод, так и всего etcd-кластера.

В предыдущей статье мы подробно рассмотрели перегенерацию SSL-сертификатов и static-манифестов для Kubernetes, а также вопросы связанные восстановлением работоспособности Kubernetes. Эта статья будет посвящена целиком и полностью восстановлению etcd-кластера.


Для начала я сразу должен сделать оговорку, что рассматривать мы будем лишь определённый кейс, когда etcd задеплоен и используется непосредственно в составе Kubernetes. Приведённые в статье примеры подразумевают что ваш etcd-кластер развёрнут с помощью static-манифестов и запускается внутри контейнеров.

Для наглядности возьмём схему stacked control plane nodes из предыдущей статьи:

(стрелочки указывают на связи клиент --> сервер)(стрелочки указывают на связи клиент --> сервер)

Предложенные ниже команды можно выполнить и с помощью kubectl, но в данном случае мы постараемся абстрагироваться от плоскости управления Kubernetes и рассмотрим локальный вариант управления контейнеризированным etcd-кластером с помощью crictl.

Данное умение также поможет вам починить etcd даже в случае неработающего Kubernetes API.

Подготовка

По этому, первое что мы сделаем, это зайдём по ssh на одну из master-нод и найдём наш etcd-контейнер:

CONTAINER_ID=$(crictl ps -a --label io.kubernetes.container.name=etcd --label io.kubernetes.pod.namespace=kube-system | awk 'NR>1{a=$1} END{print a}')

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

alias etcdctl='crictl exec "$CONTAINER_ID" etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt'

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

Если что-то пошло не так и вы не можете сделать exec в запущенный контейнер, посмотрите логи etcd:

crictl logs "$CONTAINER_ID"

А также убедитесь в наличии static-манифеста и всех сертифиткатов в случае если контейнер даже не создался. Логи kubelet так же бывают весьма полезными.

Проверка состояния кластера

Здесь всё просто:

# etcdctl member list -w table+------------------+---------+-------+---------------------------+---------------------------+------------+|        ID        | STATUS  | NAME  |        PEER ADDRS         |       CLIENT ADDRS        | IS LEARNER |+------------------+---------+-------+---------------------------+---------------------------+------------+| 409dce3eb8a3c713 | started | node1 | https://10.20.30.101:2380 | https://10.20.30.101:2379 |      false || 74a6552ccfc541e5 | started | node2 | https://10.20.30.102:2380 | https://10.20.30.102:2379 |      false || d70c1c10cb4db26c | started | node3 | https://10.20.30.103:2380 | https://10.20.30.103:2379 |      false |+------------------+---------+-------+---------------------------+---------------------------+------------+

Каждый инстанс etcd знает всё о каждом. Информация о members хранится внутри самого etcd и по этому любое изменение в ней будет также обновленно и на остальных инстансах кластера.

Важное замечание, команда member list отображает только статус конфигурации, но не статус конкретного инстанса. Чтобы проверить статусы инстансов есть команда endpoint status, но она требует явного указания всех эндпоинтов кластера для проверки.

ENDPOINTS=$(etcdctl member list | grep -o '[^ ]\+:2379' | paste -s -d,)etcdctl endpoint status --endpoints=$ENDPOINTS -w table

в случае если какой-то из эндпоинтов окажется недоступным вы увидите такую ошибку:

Failed to get the status of endpoint https://10.20.30.103:2379 (context deadline exceeded)

Удаление неисправной ноды

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

Первым делом нам нужно удалить failed member:

etcdctl member remove d70c1c10cb4db26c

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

rm -rf /etc/kubernetes/manifests/etcd.yaml /var/lib/etcd/crictl rm "$CONTAINER_ID"

Команды выше удалят static-pod для etcd и дирректорию с данными /var/lib/etcd на ноде.

Разумеется в качестве альтернативы вы также можете воспользоваться командой kubeadm reset, которая удалит все Kubernetes-related ресурсы и сертифиткаты с вашей ноды.

Добавление новой ноды

Теперь у нас есть два пути:

В первом случае мы можем просто добавить новую control-plane ноду используя стандартный kubeadm join механизм:

kubeadm init phase upload-certs --upload-certskubeadm token create --print-join-command --certificate-key <certificate_key>

Вышеприведённые команды сгенерируют команду для джойна новой control-plane ноды в Kubernetes. Этот кейс довольно подробно описан в официальной документации Kubernetes и не нуждается в разъяснении.

Этот вариант наиболее удобен тогда, когда вы деплоите новую ноду с нуля или после выполнения kubeadm reset

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

Для начала убедимся что наша нода имеет валидный CA-сертификат для etcd:

/etc/kubernetes/pki/etcd/ca.{key,crt}

В случае его отсутсвия скопируейте его с других нод вашего кластера. Теперь сгенерируем остальные сертификаты для нашей ноды:

kubeadm init phase certs etcd-healthcheck-clientkubeadm init phase certs etcd-peerkubeadm init phase certs etcd-server

и выполним присоединение к кластеру:

kubeadm join phase control-plane-join etcd --control-plane

Для понимания, вышеописанная команда сделает следующее:

  1. Добавит новый member в существующий etcd-кластер:

    etcdctl member add node3 --endpoints=https://10.20.30.101:2380,https://10.20.30.102:2379 --peer-urls=https://10.20.30.103:2380
    
  2. Сгенерирует новый static-manifest для etcd /etc/kubernetes/manifests/etcd.yaml с опциями:

    --initial-cluster-state=existing--initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
    

    эти опции позволят нашей ноде автоматически добавиться в существующий etcd-кластер.

Создание снапшота etcd

Теперь рассмотрим вариант создания и восстановления etcd из резервной копии.

Создать бэкап можно довольно просто, выполнив на любой из нод:

etcdctl snapshot save /var/lib/etcd/snap1.db

Обратите внимание я намерянно использую /var/lib/etcd так как эта директория уже прокинута в etcd контейнер (смотрим в static-манифест /etc/kubernetes/manifests/etcd.yaml)

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

Восстановление etcd из снапшота

Здесь мы рассмотрим кейс когда всё пошло не так и нам потребовалось восстановить кластер из резервной копии.

У нас есть снапшот snap1.db сделанный на предыдущем этапе. Теперь давайте полностью удалим static-pod для etcd и данные со всех наших нод:

rm -rf /etc/kubernetes/manifests/etcd.yaml /var/lib/etcd/member/crictl rm "$CONTAINER_ID"

Теперь у нас снова есть два пути:

Вариант первый создать etcd-кластер из одной ноды и присоединить к нему остальные ноды, по описанной выше процедуре.

kubeadm init phase etcd local

эта команда сгенерирует статик-манифест для etcd c опциями:

--initial-cluster-state=new--initial-cluster=node1=https://10.20.30.101:2380

таким образом мы получим девственно чистый etcd на одной ноде.

# etcdctl member list -w table+------------------+---------+-------+---------------------------+---------------------------+------------+|        ID        | STATUS  | NAME  |        PEER ADDRS         |       CLIENT ADDRS        | IS LEARNER |+------------------+---------+-------+---------------------------+---------------------------+------------+| 1afbe05ae8b5fbbe | started | node1 | https://10.20.30.101:2380 | https://10.20.30.101:2379 |      false |+------------------+---------+-------+---------------------------+---------------------------+------------+

Восстановим бэкап на первой ноде:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new  --name=node1 \  --initial-advertise-peer-urls=https://10.20.30.101:2380 \  --initial-cluster=node1=https://10.20.30.101:2380mv /var/lib/etcd/member /var/lib/etcd/member.oldmv /var/lib/etcd/new/member /var/lib/etcd/membercrictl rm "$CONTAINER_ID"rm -rf /var/lib/etcd/member.old/ /var/lib/etcd/new/

На остальных нодах выполним присоединение к кластеру:

kubeadm join phase control-plane-join etcd --control-plane

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

для node1:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new \  --name=node1 \  --initial-advertise-peer-urls=https://10.20.30.101:2380 \  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380

для node2:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new \  --name=node2 \  --initial-advertise-peer-urls=https://10.20.30.102:2380 \  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380

для node3:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new \  --name=node3 \  --initial-advertise-peer-urls=https://10.20.30.103:2380 \  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
Подробнее..

Мониторинг дисковой подсистемы VMware через CIMZabbix

18.02.2021 18:15:13 | Автор: admin

В 2021 году уже известно, что Zabbix предлагает в качестве средства комплексного мониторинга инфраструктуры VMware набор шаблонов, использующих функционал Low Level Discovery (LLD) и элементы типа Host prototype, в которых создаются стандартные списочные сенсоры из известных vCenter'у. Однако отнюдь не все вендоры оборудования корректно публикуют сенсоры или счетчики своих устройств в доступном для vCenter виде. Здесь рассматривается в подробностях настройка мониторинга для всё ещё поддерживаемых, но не отображающих состояние в vCenter контроллерах дисковой подсистемы Adaptec SmartRAID. Способ получения данных может быть пригоден и для других вендоров.

Итак, задача. Есть несколько хостов ESXi, купленных порознь у разных вендоров, с разным наполнением, и есть охота заиметь под них одинаковый мониторинг. Часть хостов выдает информацию в vSphere web client, но неструктурировано - никаких красивых группировок сенсоров по слову "storage" и близко нет, другая часть вообще ничего не выдает. При этом необходимое ПО установлено! Пример:

[root@esxi-8:~] esxcli software vib list
<snip>
scsi-aacraid 6.0.6.2.1.59002-1OEM.600.0.0.2494585 Adaptec_Inc VMwareCertified 2020-08-14
arc-cim-provider 3.07-23850 Adaptec VMwareAccepted 2021-02-15
arcconf 3.07-23850 Adaptec VMwareAccepted 2021-02-15

Как видим, в списке есть и драйвер для контроллера (здесь Adaptec RAID 8805), и утилита управления arcconf, и "родной" провайдер данных для внешних служб (далее "CIM провайдер") arc-cim-provider, все последних версий. Версия VMware на хосте 6.7U3, и сенсоров состояния подсистемы хранения в ней нет. Однако, если есть провайдер, то как-то можно получить от него данные - этим и займемся.

Во-первых, как получать эти данные. В документации на VMware, помимо всего прочего, сказано, что есть сервис sfcb, который запускается при установке стороннего CIM-провайдера, и сервис openwsman, представляющий собой сервер WS-Management, к тому же, умеющий работать с более примитивными запросами CIM или WBEM. А для работы с данными протоколами есть вполне серьезный клиент pywbem, возвращающий данные в любом удобном виде. Для своей реализации мониторинга я взял более привычную мне среду программирования bash и wbemcli в качестве средства обращения к хосту ESXi.

Чтобы получить данные от хоста, необходимо на нем авторизоваться, но локального root, естественно, заббиксу никто давать не будет. Поэтому на каждом хосте, подлежащем отслеживанию, нужно создать пользователя с ограниченным доступом, но в то же время имеющего доступ к подсистеме CIM, которая в VMware ограничена дополнительно. m4ce, создавший свой вариант шаблона для ESXi-хоста, выложил инструкцию, как правильно создать пользователя для Zabbix на ESXi-хосте версий 6.х (для более ранних необходимы слегка другие команды):

/usr/lib/vmware/auth/bin/adduser -s /sbin/nologin -D -H zabbix -G rootecho "secure_zabbix_password" | /usr/lib/vmware/auth/bin/passwd --stdin zabbixvim-cmd vimsvc/auth/role_add CIM_ReadOnly Host.Cim.CimInteraction System.Anonymousvim-cmd vimsvc/auth/entity_permission_add vim.Folder:ha-folder-root 'zabbix' false CIM_ReadOnly true

Инструкция слегка избыточна, так как, если когда-то мониторинг по CIM/WBEM/WS-Man уже настраивался, роль пользователя, подобная CIM_ReadOnly, может существовать, но на чистой системе подобных ролей не найдено.

Далее самое интересное. Дело в том, что сенсоры, которые собирает VMware vCenter, находятся в пространстве имен WBEM "по умолчанию", оно же "root/cimv2", а так как информации о дисках там нет, либо она в кривом виде, нужно найти правильное пространство имен, где эти данные есть, и правильные имена классов устройств, которые нужно отслеживать. Вторая часть несколько проще - беглым поиском находятся имена классов CIM_DiskDrive, CIM_StorageVolume, CIM_Controller, от которых можно отталкиваться в поисках фактических элементов. А с первой поможет вот этот документ от VMware (PDF), содержащий ссылки на ужасно обрезанную документацию по вендорским провайдерам. Но она есть, и вуаля - для Adaptec CIM Provider найдено пространство имен "root/pmc/arc/smi_15". Из того же документа можно узнать пространства имен и для других вендоров, пусть иногда и не напрямую - например, для Emulex пространство имен "root/emulex".

Небольшой офф-топик

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

Теперь у нас есть вся необходимая информация, чтобы начать собирать какие-то данные с хоста. Но данные из wbemcli возвращаются в очень громоздком и нечитаемом виде, мало того, адресуются элементы в командной строке не очень легко, к тому же, в Zabbix нужно суметь передать структуру обнаруженных данных через тот же механизм LLD. Для этого я написал скрипт, который умеет две вещи - отдавать найденные инстансы некоего класса из определенного пространства имен в Zabbix, и отдавать необработанные данные wbemcli при запросе конкретного инстанса. Скрипт представляет собой обертку над вызовами wbemcli einи wbemcli gi, с форматированием данных в режиме обнаружения в формат, приемлемый для Zabbix'a. Шаблон для его использования находится там же, в нем настроены некоторые основные параметры отслеживаемых физических и логических дисков - для физических это состояние, температура (два варианта - один для сервера с HDD, второй для сервера с SSD, они заполняют разные параметры!), флаг состояния SMART (тоже два), счетчик оставшегося ресурса SSD и счетчики аппаратных ошибок, для логических - только состояние, и некоторые базовые триггеры на их основе. Дополнения и тесты на не-Adaptec системах приветствуются.

Напоследок: Если вы не сумели найти правильное пространство имен, в поисках поможет то, что "пространство имен" - это тоже класс, с именем __namespace, перечисление экземпляров которого можно начать с пространства "root".

Подробнее..

Продолжаем прокачивать Ansible

22.02.2021 06:06:33 | Автор: admin

Поводом для этой статьи послужил пост в чате @pro_ansible:

Vladislav ? Shishkov, [17.02.21 20:59]Господа, есть два вопроса, касаются кастомной долгой операции, например, бекапа: 1. Можно ли через ансибл прикрутить прогрессбар выполнения кастомного баша? (если через плагин, то пните в какой-нибудь пример или документацию плиз) 2. Вроде хочется для этого баша написать плагин, но встает вопрос, как быть и как решать моменты выполнения, которые идемпотентны?

Беглый поиск по задворкам памяти ничего подходящего не подсказал. Тем не менее, я точно вспомнил, что код Ansible легко читаемый, и искаропки поддерживает расширение как плагинами, так и обычными Python-модулями. А раз так, то ничего не мешает в очередной раз раздвинуть границы возможного. Hold my beer!...

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

Исходный вопрос можно свести к двум простейшим шагам:

  1. Захватить stdout команды на целевом хосте

  2. Передать его на управляющий хост.

Передаём данные на управляющий хост

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

Код на Python
# добавляем куда-нибудь сюда:# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/plugins/connection/ssh.py#L662self._add_args(    b_command,    (b"-R", b"127.0.0.1:33333:" + to_bytes(self._play_context.remote_addr, errors='surrogate_or_strict', nonstring='simplerepr') + b":33335"),    u"ANSIBLE_STREAMING/streaming set")

Как это работает? При сборке аргументов командной строки для установления ssh-соединения эта конструкция предоставит нам на целевом хосте порт 33333 по адресу 127.0.0.1, который будет туннелировать входящие соединения на контроллер - прямиком на порт 33335.

Для простоты используем netcat (ну правда, ну что за статья без котиков?): nc -lk 33335.

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

Перехватываем stdout

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

Под мысленное просто добавь воды просто добавляем щепотку своего кода:

Опять код
# в начале basic.py, рядом с прочими import'ами import socket# в функции run_command - где-нибудь тут:# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/module_utils/basic.py#L2447clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM);clientSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)clientSocket.connect(("127.0.0.1",33333));# в функции run_command - где-нибудь тут:# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/module_utils/basic.py#L2455clientSocket.send(b_chunk);# в функции run_command - где-нибудь тут# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/module_utils/basic.py#L2481clientSocket.close()

Собираем воедино и запускаем

Осталось сделать что? Правильно, определиться со способом подключения изменённых модулей в стоковый Ansible. На всякий случай напоминаю: мы поправили один connection plugin, и один модуль из стандартной библиотеки Ansible. Новичкам в этом деле могу рекомендовать статью хабраюзера chemtech с расшифровкой моего доклада на Стачке-2019 (там как раз в том числе объясняется, какие Python-модули куда складывать), ну а опытным бойцам эти пояснения вроде и не нужны :-)

Итак, время Ч. Результат в виде статичной картинки не очень показателен, поэтому я настроил tmux и запустил запись скринкаста.

Для внимательных зрителей скринкаста

В анимации можете увидеть два полезных побочных эффекта:

  • Теперь мы видим stdout всех не-Python процессов, которые запускаются Ansible'ом на целевом хосте - например, тех, что запускаются при сборе фактов;

  • Настройки переиспользования ssh-соединений из другой моей статьи позволяют получать этот самый stdout от удалённой команды уже после отключения Ansible от хоста.

Хотите ко мне на тренинг по Ansible?

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

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

Подробнее..

Kак исправить DMARC Record not found

24.02.2021 18:11:35 | Автор: admin

Если вы видите запись DMARC не найдена, запись DMARC не опубликована илизапись DMARC отсутствует, это означает, что в домене отсутствует самый эффективный и мощный механизм идентификации электронной почты, такой как DMARC.

Source: ShutterstockSource: Shutterstock

Чтобы предотвратить спуфинг электронной почты (практика злоумышленников маскироваться под конкретного пользователя или подключенного к сети устройства с целью похищения данных), все домены должны иметь систему авторизации электронной почты. Наверное, вы слышали о механизмах SPF и DKIM. Но дело в том, что ни SPF, ни DKIM сами по себе не могут остановить заимствование вашего домена и не могут предотвратить спуфинг электронной почты. DMARC (Domain-based Message Authentication, Reporting & Conformance) приходит на помощь. Он сочетает в себе механизмы SPF и DKIM и обеспечивает 100% защиту от атак.

DMARC может защищать от фишинг атак. Фишинг - это мошенническая попытка получить конфиденциальную информацию. Выдавая себя за правомерного индивида, хакеры манипулируют жертвами для выполнения определенных действий. По данным Verizon Data Breach Investigations Report 2018, Фишинг и претекстинг составляют 93% нарушений. 80% всех нарушений связаны с учетными данными DBIR.

Итак, как исправить и добавить отсутствующую запись DMARC?

Возможно, вы получили упомянутое ниже с помощью какого-нибудь инструмента проверки DMARC:

  • No DMARC record

  • No DMARC record found

  • DMARC record is missing

  • DMARC record not found

  • No DMARC record published

  • DMARC policy not enabled

  • Unable to find DMARC record

В зависимости от того, чего вы хотите достичь. Есть 2 возможных варианта.

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

Ответ очень прост. Технически исправление Записи DMARC Не найдено буквально означает добавление записи DNS TXT в субдомен _dmarc.yourdomain.com в соответствии со спецификацией DMARC.

Простую запись DMARC можно рассмотреть на следующем примере:

v=DMARC1; p=none; rua=mailto:whateveryoulike@yourdomain.com

Получилось! Недостающая запись DMARC была успешно добавлена.

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

Вариант 2: Обеспечьте 100% защиту от атак с изменением авторства и спуфинга.

Чтобы добиться 100% защиты, вам нужно понять механизм системы DMARC и то, как она работает. Трудно добиться 100% защиты от спуфинга электронной почты; это требует усердия и некоторого времени (обычно более 2 месяцев и зависит от того, насколько сложна ваша инфраструктура электронной почты).

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

Процесс начинается с простого ввода базовой записи DMARC.

3 шага для устранения проблемы No DMARC record found

1. Опубликуйте запись SPF.

Используйте бесплатный генератор SPF записи EasyDMARC или любой другой, чтобы создать свою запись и опубликовать сгенерированную запись в вашем DNS.

Запись SPF выглядит следующим образом.

v=spf1 include:spf.easydmarc.com include:amazonses.com ip4:198.105.215.71/32 -all

2. Настройте идентификацию DKIM.

Далее вам нужно настроить свой почтовый сервер. Для этого вы можете использовать бесплатный генератор DKIM записи EasyDMARC для идентификации DKIM. Вот автоматический скрипт, который поможет вам настроить почтовый сервер Linux с помощью DKIM.

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

3. Опубликуйте запись DMARC.

Наконец готовы настроить запись DMARC. Используйте бесплатный генератор DMARC записи EasyDMARC и опубликуйте сгенерированную запись в свой DNS.Во-первых, настоятельно рекомендуется иметь политику мониторинга (p=none). После получения успешных результатов мониторинга система предложит вам изменить опубликованную политику.

Не используйте политику p=reject в самом начале, если вы не уверены, что у вас есть правильная конфигурация и видимость в вашей почтовой инфраструктуре.

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

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

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

Эти статьи помогут вам настроить DMARC-записи от различных провайдеров DNS:

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

Подробнее..

Подготовка шаблона vApp тестовой среды VMware vCenter ESXi

25.02.2021 10:21:06 | Автор: admin

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

Перед вами пошаговое руководство по подготовке шаблона vApp для VMware Cloud Director, включающего в себя vCenter Server Appliance и 3 гипервизора ESXi, с целью снижения временных затрат на развертывании тестовой инфраструктуры VMware.

Оглавление
  1. Что мы будем делать

    1.1. Список VM в шаблон

    1.2. Требования

  2. Схема логической топологии

  3. Подготовка Working Environment

    3.1. Установка ESXi

    3.2. Установка ManagementVM

    3.3. Установка vCenter Server Appliance

  4. Создание шаблона vApp

    4.1. Подготовка vApp

    4.2. Создание ESXi VM в vApp

    4.3. Кастомизация ESXi в vApp

    4.4. Установка vCenter Server Appliance в vApp

    4.5. Установка Windows Server 2019 в vApp

    4.6. Установка Ubuntu 18.04 LTS в vApp

    4.7. Удаление ISO приводов и сетевых адаптеров

  5. Выгрузка vApp шаблона из Working Environment

  6. Загрузка vApp в VMware Cloud Director

1. Что мы будем делать

Мы подготовим максимально гибкий шаблон без привязки к адресу подсети, доменному имени, количеству выделяемых ресурсов и т.п. Будем делать так, чтобы при развертывании шаблона администратор мог произвести тонкую настройку. Подготовка шаблона выполняется в сети 10.0.0.0/24, а за стандартные значения при развертывании готового шаблона примем домен Domain.local и сеть 192.168.2.0/24.

Имя домена domain.local и сеть 192.168.2.0/24 выберем как значения по умолчанию, которые можно изменять в процессе развёртывания шаблона.

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

1.1. Список VM в шаблоне

  1. VMware ESXi 1 Гипервизор;

  2. VMware ESXi 2 Гипервизор;

  3. VMware ESXi 3 Гипервизор;

  4. VMware vCenter Server Appliance with Embedded Platform Services Controller в конфигурации Tiny;

  5. Ubuntu 18.04 LTS в качестве общего NFS хранилища;

  6. Windows Server 2019 в качестве DNS сервера и Management machine. В последствии, с нее будет производится управления vCenter.

1.2. Требования

  1. VDC в VMware Cloud Director:

    a. 28 vCPU;

    b. 50GB RAM;

    c. 2TB Storage.

  2. Дистрибутивы ПО:

    a. ISO с дистрибутивом VMware ESXi 6.7U3b;

    b. ISO (или OVA) с дистрибутивом VMware vCenter Server Appliance 6.7U3b;

    c. ISO (или OVA) с Windows Server 2019;

    d. ISO (или OVA) с Ubuntu1804.

  3. Дополнительное ПО (опционально):

    a. Браузер Google Chrome;

    b. Текстовый редактор Notepad++;

    c. SFTP клиент WinSCP.

    d. 7-Zip

  4. Убедитесь, что в нашей локальной сети на уровне vCenter облачного провайдера переключены в состоянии Accept политики Promiscuous mode и Forged transmits. Иначе не будет связи между сетью виртуального дата-центра и сетью внутри подготавливаемого шаблона. Здесь об этом рассказывается подробнее.

Дистрибутивы продуктов VMware можно скачать с официального сайта, зарегистрировавшись в программе обучения и получив VMware Evaluation License на 60 дней.

Возможностей VMware Cloud Director для подготовки данного шаблона будет недостаточно, поэтому сначала развернём нашу рабочую среду Working Environment в виртуальном дата-центре VMware Cloud Director.

В рабочую среду мы установим ESXi гипервизор, vCenter Server Appliance и Windows Server 2019 в качестве ManagementVM. Подготовку шаблона будем выполнять, используя интерфейс vSphere Client в рабочей среде.

2. Схема логической топологии

3. Подготовка Working Environment

3.1. Установка ESXi

В VDC создаём каталог (Libraries -> Catalogs -> New) и загружаем в него ISO с установщиком ESXi.

Создаём VM temp-ESXi1 ESXi 6.7.

Выбираем загрузку с ISO.

Назначаем VM 24 vCPU, 24 Cores per socket, 32GB RAM и 5GB Storage. Подключаем сеть к виртуальной машине.

ESXi требует для развёртывания минимум двухъядерные процессоры. Установка на 24 одноядерных vCPU завершится ошибкой, поэтому необходимо задать отличный от единицы параметр Cores per socket.

Запускаем VM.

Выполняем установку, нажимая Enter или F11

В процессе установки задаём пароль root

Нажимаем F11 и дожидаемся завершения установки

По завершению установки нажимаем Enter и перезагружаемся

Дожидаемся окончания загрузки, нажимаем F2, вводим пароль root

Переходим в настройки сети Configure Management Network.

Задаём статический IP.

Отключаем IPv6.

Перезагружаем VM для применения отключения IPv6. Для применения остальных настроек достаточно перезапуска сетевого адаптера.

В VMware Cloud Director подключаем к temp-ESXi1 ещё один диск на 1ТБ. Это будет наш Datastore. Перезагружаем VM temp-esxi1.

3.2. Установка ManagementVM

Разворачиваем VM с Windows Server 2019. Настраиваем доступ по RDP.

Подключаемся по RDP к VM c Windows Server. Устанавливаем роль DNS сервера.

Создаём Forward Lookup Zone template.local

Создаём Reverse Lookup Zone для 0.0.10.in-addr.arpa

Создаём A и PTR записи в созданных зонах для temp-esxi01 и vcentersa1.

Важно! PTR запись для vCenter должна быть обязательно. Без неё установка vCenter завершится ошибкой.

Настраиваем DNS Forwarders.

Настраиваем DNS сервер 127.0.0.1 на сетевом интерфейсе.

3.3. Установка vCenter Server Appliance

Монтируем образ VMware-VCSA-all-6.7.0-14367737.iso на ManagementVM и извлекаем из ISO E:\vcsa\VMware-vCenter-Server-Appliance-6.7.0.40000-14367737_OVF10.ova

Переходим в vcd.cloud4y.ru в свой VDC. Загружаем в каталог OVA шаблон с vCenter. Для загрузки понадобится 300 ГБ свободного места в VDC.

Получаем ошибку

В логе видим текст ошибки Validation failed for the OVF file you provided: Fatal: Line/char 867/92: cvc-minInclusive-valid: Value '-100' is not facet-valid with respect to minInclusive '0' for type 'unsignedShort'. Fatal: Line/char 867/92: cvc-attribute.3: The value '-100' of attribute 'ovf:id' on element 'OperatingSystemSection' is not valid with respect to its type, 'unsignedShort'..

VMware Cloud Director не принимает значение -100 на строке 867 *.ovf файла.

Возвращаемся на ManagementVM и с помощью архиватора 7-zip извлекаем *.ovf и *.mf файлы. OVA представляет из себя архив tar, и, как правило, содержит файлы виртуальных дисков *.vmdk, файл конфигурации VM/vApp *.ovf, список файлов в архиве и их контрольные суммы *.mf

Открываем *.ovf через текстовый редактор и ищем -100 на 867 строке и заменяем на 1

Теперь нам нужно пересчитать SHA1 для *.ovf файла и изменить это значение в *.mf файле

Для расчета хеша используем PowerShell

(Get-FileHash C:\Users\Administrator\Desktop\VMware-vCenter-Server-Appliance-6.7.0.40000-14367737_OVF10.ovf -Algorithm SHA1).Hash.ToLower()

Заменяем значение в *.mf файле

Запаковываем *.ovf и *.mf обратно в OVA шаблон

Пробуем загрузить OVA в VDC ещё раз.

По завершению загрузки разворачиваем vApp с vCenter в нашем VDC

Выделяемые ресурсы vCPU, RAM, Storage не меняем. Больше ресурсов не требуется, а при меньшем значении могут возникнуть проблемы с производительностью.

Конфигурируем сеть.

На шаге 8 ничего не меняем. Мы изменим эти параметры позже. Нажимайте Next. Если при развёртывании шаблона что-то пойдёт не так, придётся заполнять эти поля ещё раз при повторном развёртывании.

Дожидаемся окончания развёртывания и перемещаем VM в vApp vcsa + esxi для наглядности. С технической точки зрения разницы нет.

По окончанию перемещения наш vApp vcsa + esxi выглядит следующим образом.

Переходим в Guest Properties temp-vcentersa1 и нажимаем Edit

Заполняем поля, указанные в таблице ниже. Остальные поля заполнять не обязательно

Наименование параметра

Описание параметра

Значение параметра

Domain Name

Имя домена (DNS суффикс)

template.local

Host Network IP Address Family

Семейство IP

ipv4

Host Network Mode

IP Mode

static

Host Network IP Address

IP адрес vCenter

10.0.0.110

Host Network Prefix

Префикс подсети

24

Host Network Default Gateway

IP шлюза по умолчанию

10.0.0.1

Host Network DNS Servers

Адреса DNS серверов

10.0.0.102

Host Network Identity

FQDN vCenter

temp-vcentersa1.template.local

Directory Username

Логин учетной записи администратора в SSO домене. Используется для аутентификации в веб интерфейсе vCenter

administrator@vsphere.local

Directory Password

Пароль учетной записи администратора в SSO домене. Используется для аутентификации в веб интерфейсе vCenter

*пароль*

Directory Domain Name

Имя домена SSO. Должно соответствовать домену, указанному в логине учетной записи администратора

vsphere.local

Root Password

Пароль root от консоли vCenter

*пароль*

Tools-based Time Synchronization Enabled

Использовать VM Tools для синхронизации времени с гипервизором.

+

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

Запускаем VM и ждём 5-10 минут.

Через браузер с ManagementVM переходим на https://temp-vcentersa1.template.local:5480/ и дожидаемся окончания установки.

Нажимаем Set Up

Вводим пароль root, указанный ранее в Guest Properties

На шаге 2 проверяем корректность настроек. Редактируем при необходимости.

На шаге 3 создаём новый SSO домен.

Проверяем корректность параметров и нажимаем Finish.

Если установка завершится ошибкой на 2%, то проблема почти наверняка кроется в некорректно созданной PTR записи для vCenter.

Дожидаемся окончания установки

Переходим по адресу https://temp-vcentersa1.template.local:443, выбираем LAUNCH VSPHERE CLIENT (HTML5)

Вводим учётные данные Администратора SSO домена

Скачиваем сертификат CA и устанавливаем в систему https://temp-vcentersa1.template.local/certs/download.zip .

Необходимо установить сертификат download.zip\certs\win\*.crt в доверенные корневые центры сертификации ManagementVM и перезапустить браузер.

В vCenter создаём дата-центр.

В дата-центре создаём кластер.

Включаем vSphere DRS.

vSphere HA и VSAN оставляем выключёнными. C 1 ESXi гипервизором DRS работать не будет, но он должен быть включён для работы с vApp.

Переходим в Configure - > Configuration > Quickstart кластера temp-Cluster и добавляем temp-ESXi1, нажав ADD.

Выбираем наш хост temp-esxi1.template.local и вводим учётные данные root.

Принимаем его сертификат и завершаем работу с Quickstart. Нужно добавить temp-esxi1 в кластер. Продолжать настройку кластера необходимости нет.

Добавляем Datastore в наш кластер. Кликаем правой кнопкой мыши по кластеру и выбираем Storage -> New Datastore.

Выбираем тип VMFS

Задаём имя Datastore и выбираем подключенный ранее диск на 1 ТБ на temp-ESXi1.

На шаге 4 указываем использование всего раздела на 1 ТБ и завершаем работу мастера.

Выводим temp-esxi1 из Maintenance Mode

Подготовка инфраструктуры для создания шаблона завершена.

4. Создание шаблона vApp

4.1. Подготовка vApp

Кликаем на кластер правой кнопкой мыши и создаём новый vApp: vApp_vCenter6.7_3ESXi6.7_UbuntuNFS_WindowsDNS

В vApp будут следующие VM:

  1. ESXi01

  2. ESXi02

  3. ESXi03

  4. vCenterSA01

  5. WindowsDNS

  6. UbuntuNFS01

UbuntuNFS это имитация внешней СХД. На ней будет Datastore, доступный всем ESXi хостам.

ESXi0x устанавливаем из ISO. vCenterSA01, WindowsDNS, UbuntuNFS можно развернуть из OVA шаблонов.

Добавим ISO с установщиком ESXi в temp-Datastore. Переходим в Datastores -> temp-Datastore -> Files, создаём папку ISO и загружаем в неё ISO образ установщика ESXi

4.2. Создание ESXi VM в vApp

На шаге 2 задаём имя VM.

На шаге 3 выбираем vApp, в котором будут размещены VM.

На шаге 6 выбираем тип гостевой ОС.

На шаге 7 выбираем 2 vCPU, 4GB RAM, 5GB Storage и подключаем ISO. Разверните подраздел CPU и отметьте пункт Hardware virtualization.

Перейдите на вкладку VM Options и снимите отметку с пункта Secure Boot.

Клонируем VM ESXi01 в VM ESXi02 и в VM ESXI03.

Запускаем vApp и выполняем установку ESXi01, ESXi02, ESXi03.

Настраиваем на ESXi IP адреса:

ESXi01 - 10.0.0.11

ESXi02 - 10.0.0.12

ESXi03 - 10.0.0.13

На каждом ESXi хосте включаем доступ по SSH (F2 -> Troubleshooting Options - > Enable SSH)

4.3. Кастомизация ESXi в vApp

Добавим ESXi хостам возможность кастомизации сетевых параметров из интерфейса VMware Cloud Director (и vSphere Client). Для этого подключимся с помощью WinSCP к хосту, перейдём в каталог /etc/rc.local.d и откроем текстовым редактором файл local.sh

Заменим содержимое local.sh следующим скриптом:

#!/bin/sh#Customization script for ESXi01getprops_from_ovfxml() {/bin/python - <<EOSfrom xml.dom.minidom import parseStringovfEnv = open("$1", "r").read()dom = parseString(ovfEnv)section = dom.getElementsByTagName("PropertySection")[0]for property in section.getElementsByTagName("Property"):key = property.getAttribute("oe:key").replace('.','_')value = property.getAttribute("oe:value")print ("{0}={1}".format(key,value))dom.unlink()EOS}#С помощью VMware Tools получаем ovf.xml с параметрами, переданными через Guest Properties/sbin/vmtoolsd --cmd='info-get guestinfo.ovfEnv' >/tmp/ovf.xml 2>/dev/nulleval `getprops_from_ovfxml /tmp/ovf.xml`#Проверяем, что в Guest Properties включена кастомизацияif [ $enablecustomization1 = "enabled" ] ;thenesxcfg-init --set-boot-progress-text "Applying OVF customization..."#Изменяем пароль rootecho $rootpassword1 | passwd --stdin root#Задаем FQDN ESXi хостаesxcli system hostname set --fqdn=$fqdn1#Задаем настройки IPesxcli network ip interface ipv4 set -i vmk0 -I $ipaddr1 -N $netmask1 -g $defaultgateway1 -t static#Очищаем список DNS серверовesxcli network ip dns server remove -a#Добавляем DNS серверesxcli network ip dns server add --server=$dnsserver1#Перезапускаем сетевой интерфейс для применяния настроекesxcli network ip interface set -e false -i vmk0esxcli network ip interface set -e true -i vmk0esxcfg-init --set-boot-progress-text "OVF customization applied"elseesxcfg-init --set-boot-progress-text "OVF customization disabled."firm -f /tmp/ovf.xmlexit 0

Сохраним файл и выключим хост ESXi из меню выключения.

Важно: для каждого ESXi хоста применятся своя версия скрипта.

Это связано с тем, что в ovf.xml передаются все параметры Guest Properties каждой VM в vApp.

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

$rootpassword1 заменить на $rootpassword2

$ipaddr1 заменить на $ipaddr2

и т.д.

Скрипт для ESXi02
#!/bin/sh#Customization script for ESXi02getprops_from_ovfxml() {/bin/python - <<EOSfrom xml.dom.minidom import parseStringovfEnv = open("$1", "r").read()dom = parseString(ovfEnv)section = dom.getElementsByTagName("PropertySection")[0]for property in section.getElementsByTagName("Property"):key = property.getAttribute("oe:key").replace('.','_')value = property.getAttribute("oe:value")print ("{0}={1}".format(key,value))dom.unlink()EOS}#С помощью VMware Tools получаем ovf.xml с параметрами, переданными через Guest Properties/sbin/vmtoolsd --cmd='info-get guestinfo.ovfEnv' >/tmp/ovf.xml 2>/dev/nulleval `getprops_from_ovfxml /tmp/ovf.xml`#Проверяем, что в Guest Properties включена кастомизацияif [ $enablecustomization2 = "enabled" ] ;thenesxcfg-init --set-boot-progress-text "Applying OVF customization..."#Изменяем пароль rootecho $rootpassword2 | passwd --stdin root#Задаем FQDN ESXi хостаesxcli system hostname set --fqdn=$fqdn2#Задаем настройки IPesxcli network ip interface ipv4 set -i vmk0 -I $ipaddr2 -N $netmask2 -g $defaultgateway2 -t static#Очищаем список DNS серверовesxcli network ip dns server remove -a#Добавляем DNS серверesxcli network ip dns server add --server=$dnsserver2#Перезапускаем сетевой интерфейс для применяния настроекesxcli network ip interface set -e false -i vmk0esxcli network ip interface set -e true -i vmk0esxcfg-init --set-boot-progress-text "OVF customization applied"elseesxcfg-init --set-boot-progress-text "OVF customization disabled."firm -f /tmp/ovf.xmlexit 0
Скрипт для ESXi03
#!/bin/sh#Customization script for ESXi03getprops_from_ovfxml() {/bin/python - <<EOSfrom xml.dom.minidom import parseStringovfEnv = open("$1", "r").read()dom = parseString(ovfEnv)section = dom.getElementsByTagName("PropertySection")[0]for property in section.getElementsByTagName("Property"):key = property.getAttribute("oe:key").replace('.','_')value = property.getAttribute("oe:value")print ("{0}={1}".format(key,value))dom.unlink()EOS}#С помощью VMware Tools получаем ovf.xml с параметрами, переданными через Guest Properties/sbin/vmtoolsd --cmd='info-get guestinfo.ovfEnv' >/tmp/ovf.xml 2>/dev/nulleval `getprops_from_ovfxml /tmp/ovf.xml`#Проверяем, что в Guest Properties включена кастомизацияif [ $enablecustomization3 = "enabled" ] ;thenesxcfg-init --set-boot-progress-text "Applying OVF customization..."#Изменяем пароль rootecho $rootpassword3 | passwd --stdin root#Задаем FQDN ESXi хостаesxcli system hostname set --fqdn=$fqdn3#Задаем настройки IPesxcli network ip interface ipv4 set -i vmk0 -I $ipaddr3 -N $netmask3 -g $defaultgateway3 -t static#Очищаем список DNS серверовesxcli network ip dns server remove -a#Добавляем DNS серверesxcli network ip dns server add --server=$dnsserver3#Перезапускаем сетевой интерфейс для применяния настроекesxcli network ip interface set -e false -i vmk0esxcli network ip interface set -e true -i vmk0esxcfg-init --set-boot-progress-text "OVF customization applied"elseesxcfg-init --set-boot-progress-text "OVF customization disabled."firm -f /tmp/ovf.xmlexit 0

После того, как мы добавили скрипты на каждый ESXi хост, через vCenter кликаем на VM -> Configure -> vApp Options -> Edit

Отмечаем пункт Enable vApp options, а на вкладке OVF Details отмечаем пункт VMware Tools. Это нужно для того, чтобы VMware Tools передали ovf.xml внутрь гостевой ОС ESXi

Переходим VM -> Configure -> vApp Options, пролистываем вниз и нажимаем ADD.

Для ESXi01 нужно добавить следующие Properties:

  1. enablecustomization1;

  2. rootpassword1;

  3. fqdn1;

  4. ipaddr1;

  5. netmask1;

  6. defaultgateway1;

  7. dnsserver1.

В поле Category указываем название подраздела, в поле Label отображамое имя параметра, а в поле Key ID имя переменной, которую обрабатывает скрипт кастомизации.

Эти параметры можно будет задать в интерфейсе VMware Cloud Director в процессе развёртывания шаблона. Скриншот для наглядности ниже.

Нажимаем ADD и добавляем Properties.

На вкладке Type мы можем выбрать тип параметра, в нашем случае все параметры строковые (String), и выбрать значение по умолчанию (Default value). Это значение будет автоматически подставлено при развёртывании шаблона.

Создаём property для каждого параметра на каждом ESXi хосте.

Корректно заполненные Properties должны выглядеть, как на скриншотах ниже.

4.4. Установка vCenter Server Appliance в vApp

Добавим OVA с vCenter Server Appliance vApp. Конфигурировать и запускать не будем.

Выбираем OVA шаблон vCenter

В процессе развёртывания оставляем все значения По умолчанию. Просто нажимаем Next на каждом этапе и дожидаемся окончания развёртывания.

Затем необходимо установить Windows Server 2019 и Ubuntu 18.04 LTS. Это можно сделать, используя ISO-образы, но я пойду более простым путём и разверну их из OVA шаблонов, предварительно скачанных из публичных каталогов VMware Cloud Director (vcd.cloud4y.ru).

4.5. Установка Windows Server 2019 в vApp

Разворачиваем Windows Server из OVA шаблона. Запускаем VM.

Включаем удалённое управление по RDP.

Устанавливаем роль DNS сервера.

Создаём Forward Lookup Zone для domain.local.

Создаём Reverse Lookup Zone для 2.168.192.in-addr.arpa.

Выключаем VM.

4.6. Установка Ubuntu 18.04 LTS в vApp

Концепция следующая:

При развёртывании шаблона в VMware Cloud Director подключаем к VM с Ubuntu 18.04 LTS дополнительный диск, форматируем его в ext4 и расшариваем в нашей подсети средствами NFS.

Настраиваем сеть. Устанавливаем обновления: apt install update && apt install upgrade -y

Устанавливаем NFS сервер: apt install nfs-kernel-server nfs-common -y

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

Редактируем /etc/fstab

Редактируем /etc/exports

Выключаем все запущенные VM в vApp.

4.7. Удаление ISO приводов и сетевых адаптеров

Переходим в настройки каждой VM и удаляем все CD-приводы и сетевые адаптеры каждой VM в vApp. CD-приводы нам более не требуются. Сетевые адаптеры удаляем во избежание конфликтов при развёртывании шаблона.

5. Выгрузка vApp шаблона из Working Environment

Выгрузка шаблона из vCenter.

Теперь мы можем выгрузить шаблон.

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

По окончанию скачивания получаем набор файлов, готовых к загрузке в VMware Cloud Director. Общий размер 11,5 ГБ, но в VMware Cloud Director потребуется около 350ГБ, т.к. у нас используются Thin (тонкие) диски, а VMware Cloud Director рассчитывает размер не по текущему размеру диска, а по максимальному (до которого диски могут быть расширены).

6. Загрузка vApp в VMware Cloud Director

Переходим в vcd.cloud4y.ru и загружаем vApp из OVF.

Нажимаем Browse и выбираем все файлы, которые мы экспортировали из vCenter.

На последующих шагах принимаем EULA и не вносим изменений в параметры развёртывания. Нажимаем Next-> Next -> -> Finish.

Дожидаемся окончания загрузки. Теперь мы можем сохранить готовый vApp в каталог.

Надеемся, что наш туториал по подготовке шаблона vApp тестовой среды VMware vCenter + ESXi в VMware Cloud Director будет вам полезен при работе с вложенной виртуализацией и подготовке среды для неё. Да, в первую очередь информация будет полезна инженерам облачного провайдера. Но для понимания принципов работы облачной инфраструктуры статью можно прочитать и другим техническим специалистам.

Спасибо за внимание!


Что ещё интересного есть в блогеCloud4Y

Пароль как крестраж: ещё один способ защитить свои учётные данные

Тим Бернерс-Ли предлагает хранить персональные данные в подах

Виртуальные машины и тест Гилева

Создание группы доступности AlwaysON на основе кластера Failover

Как настроить SSH-Jump Server

Подписывайтесь на нашTelegram-канал, чтобы не пропустить очередную статью. Пишем не чаще двух раз в неделю и только по делу.

Подробнее..

Nebula или RADIUS на примерах что выбрать для персональной аутентификации для точки доступа

25.02.2021 12:15:55 | Автор: admin


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


В статье Настройка WPA2 Enterprise c RADIUS мы описали вариант использования корпоративной схемы аутентификации с внешним сервером RADIUS. Для создания такой системы нужен ни много ни мало сам сервер RADIUS (для этого нам понадобилось развернуть на отдельной машине с Linux пакет Free RADIUS).


Напомню, для чего это нужно. Когда используется простая схема WPA2 Personal c единственным ключом на все беспроводные устройства это годится только для небольших сетей. Основное ограничение в том, что заменить такой ключ весьма непросто придётся вводить заново на всех устройствах всех пользователей, кто подключается к WiFi сети. А менять рано или поздно придётся. Среди причин наиболее частыми называют компрометацию со стороны пользователей и сугубо кадровые процессы: увольнение, перевод на другую работу и так далее.


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

Но что делать, если такая в виде отдельного сервера RADIUS (пусть даже и виртуального) недоступна. В статье Что останется в серверной прорисовывается вполне понятная картина: по вполне естественным причинам в небольшой серверной в лучшем случае остаётся сетевое оборудование для удалённого доступа и вспомогательные системы вроде NAS для резервных копий рабочих станций.


Для совсем маленьких организаций может встать ещё и такой вопрос: А где размещать виртуальную машину с RADIUS?


Можно арендовать виртуалку на облачном сервисе. Это стоит определённых денег. Мало того, о такой виртуальной машине всё равно нужно заботиться: проводить обновление, аудит безопасности, читать логи, следить за состоянием файловой системы и так далее То есть это вполне себе ощутимые затраты: как финансовые, так и трудовые. И всё только ради RADIUS?


А можно как-то по-другому? Чтобы и сервис авторизации получить, и виртуалку разворачивать не пришлось и сделать всё это бесплатно? Оказывается, у Zyxel есть целых два варианта, как это можно сделать красиво, просто и без лишних затрат.


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


Проверьте может быть RADIUS есть в вашем шлюзе?


В шлюзах от Zyxel уже есть встроенный сервис RADIUS. То есть если используется, например, сетевой экран, то в нём уже есть всё необходимое для аутентификации WPA2 Enterprise.


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


Практически в любой современной ИТ инфраструктуре можно встретить межсетевой экран для доступа в Интернет. В случае с оборудованием от Zyxel можно получить не только защиту от внешних (и внутренних!) атак, но и систему аутентификации WPA2 Enterprise c реквизитами для отдельных пользователей, и ничего устанавливать не надо, всё работает из коробки.


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


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


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


Для примера такой схемы аутентификации прекрасно подойдёт USG FLEX 200 уже не начальный уровень, но и не топовая модель в линейке. Эта модель хорошо подходит в качестве межсетевого экрана для небольших и средних офисов.


Коротко о межсетевом экране USG FLEX 200:


  • поддержка облачных технологий Zyxel Security Cloud (в первую очередь это отличный инструмент для сбора информации об угрозах из различных источников) и Cloud Query Express (облачная база данных для надёжной защиты от вирусов);
  • фильтрация URL и IDP для отражения атак извне;
  • патруль приложений и Контентная фильтрация для контроля доступа пользователей к приложениям и web-сайтам.


Рисунок 1. Межсетевой экран USG FLEX 200.


В качестве точки для нашей демонстрации выберем ту же самую NWA210AX, уже знакомую нам по статье Настройка WPA2 Enterprise c RADIUS.


Коротко о точке доступа WA210AX устройстве:


  • поддержка Wi-Fi 6;
  • 6 пространственных потоков (4x4:4 в 5 ГГц, 2x2:2 в 2,4 ГГц);
  • поддержка OFDMA и MUMIMO;
  • имеется как локальное, так и облачное управление через Zyxel Nebula.


Рисунок 2. Точка доступа NWA210AX.


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


От слова к делу настраиваем встроенный сервис RADIUS


Начинаем с получения IP адреса. Для этого воспользуемся утилитой ZON Zyxel One Network Utility, которая собирает данные обо всех устройствах Zyxel в доступном сегменте сети.


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


Рисунок 3. Утилита ZON для нашего примера


Итак, мы знаем IP адреса устройств, к которым нам предстоит подключиться.


Настройка службы на межсетевом экране


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



Рисунок 4. Окно входа на USG FLEX 200.



Рисунок 5. Dashboard на USG FLEX 200.


Далее переходим в раздел Configuration System Auth. Server.


Первое что необходимо включить саму службу сервера аутентификации


Активируем элемент Enable Authentication Server, нажимаем Apply внизу экрана и наш сервис переходит в активное состояние.



Рисунок 6. Enable Authentication Server.


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


Нажимаем экранную кнопку Add для вызова окна Add Trusted Client.



Рисунок 7. Окно Add Trusted Client.


Соответственно, указываем в поле Profile Name имя сети, в нашем случае inside_network


IP Address и Netmask (адрес и маску подсети) 192.168.1.0 255.255.255.0.


Поле Description заполняется по желанию.


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


Нажимаем OK для окна Add Trusted Client и потом кнопку Apply для всего раздела Auth. Server. Всё, наши значения должны примениться.


После этого переходим в раздел Configuration Object User/Group и добавляем учётные записи для нужных пользователей.



Рисунок 8. Учётные записи User/Group в разделе Object (Configuration).


Нажимаем Add появится окно Add A User.



Рисунок 9. Окно ввода пользователя.


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



Рисунок 10. Новые учётные записи: ivan и rodeon с пометкой WiFi User.


Настройка точки доступа для использования сервиса аутентификации


В принципе, настройка точки доступа для аутентификации со встроенным RADIUS на шлюзе Zyxel производится аналогично, как и было показано в статье Настройка WPA2 Enterprise c RADIUS


Для начала подключаемся к нужному IP через окно браузера, вводим имя пользователя и пароль (по умолчания также admin и 1234).



Рисунок 11. Окно входа на NWA210AX.


Далее переходим в меню Configuration AP management Wlan setting.


Нас интересует область MB SSID setting. Здесь нужно отредактировать профили Wiz_SSD_1 и Wiz_SSD_2.



Рисунок 12. Configuration AP management Wlan setting.



Рисунок 13. Настройка профиля SSID Profile Wiz_SSD_1.


Нажимаем на кнопочку редактировать, напоминающие редакторский блокнот с карандашом. Появляется окно Edit SSID Profile Wiz_SSD_1. В нем нас интересуют настройки Security Profile Wiz_Sec_Profile_1 (такая же кнопочка редактировать в виде блокнота с карандашом). Дальше появляется окно Edit Security Profile Wiz_Sec_Profile_1.



Рисунок 14. Окно Edit Security Profile Wiz_Sec_Profile_1.


В этом окне и выполняем необходимые настройки.


Для основного сервера вводим IP address, UDP Port и секретный ключ.


Для подтверждения нажимаем OK.


Аналогичным образом редактируем второй профиль SSID Profile Wiz_SSD_2.


Нажимаем Apply в разделе Configuration AP management Wlan setting для применения настроек.


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


В статье Настройка WPA2 Enterprise c RADIUS была иллюстрация на примере Mac OS X. Теперь для разнообразия подключим ноутбук с Windows 10.


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



Рисунок 15. Настройка клиента.


Вводим необходимые реквизиты и подключаемся к системе.


Мы сейчас прошли весь этап настройки с внешним готовым сервисом RADIUS на межсетевом экране. Даже без стандартных действий для серверной системы: установки пакетов, настройки firewall, тестирования самой сервисной службы всё равно операция заняла достаточно много времени. Можно ли это сделать побыстрее и с меньшими трудозатратами? Можно, если использовать Zyxel Nebula. Но об этом ниже.


Отказоустойчивость и второй RADIUS сервер


Для среды production в компаниях уровня Enterprise нужно отказоустойчивое решение. Для таких целей часто используется второй сервер аутентификации.


Довольно большое распространение получили системы на базе MS Windows, где, благодаря серверной роли Network Policy Server и авторизации в Active Directory, можно настроить два сервера аутентификации для WPA2 Enterprise, и у них будет единая синхронизированная база данных пользователей и ключей.


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


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

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


Но всё можно решить ещё проще при использовании аутентификации в облачном сервисе Zyxel Nebula. В этом случае за отказоустойчивость самой системы отвечает мощный промышленный программно-аппаратный комплекс. Разумеется, серверы Nebula размещены в ЦОД, выполняются все необходимые процедуры по поддержанию заявленного уровня высокой доступности и так далее. Единственное, что требуется от локального офиса канал в Интернет.


Пользователю остаётся только подключить устройство к облаку Zyxel Nebula и воспользоваться всеми заявленными преимуществами.


Использование Nebula на конкретном примере


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


В рамках данной статьи не будем детально описывать весь процесс первичной настройки сервиса Zyxel Nebula, так как он касается не только беспроводной сети, но и многих других аспектов сетевой инфраструктуры.


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


А сейчас мы просто переходим на сайт nebula.zyxel.com вводим пароль и попадаем в облачный интерфейс.



Рисунок 16. Вход в Zyxel Nebula.


Вначале нужно зарегистрировать точку доступа. Можно воспользоваться специальным приложением для IOS или Android и просто отсканировать QR-код. Это удобно если устройство находится под рукой. Если нужно зарегистрировать удалённо, это можно сделать, зная MAC адрес и серийный номер, указав их в интерфейсе. Это метод наиболее универсальный, им и воспользуемся.


Обратите внимание. Для настройки устройств с Zyxel Nebula нам нужно только, чтобы точка доступа была подключена к сети, при этом используется исходящее соединение. То есть не нужно открывать входящие порты, пробрасывать трафик через PAT всё выполняется в рамках исходящего подключения к облаку.


Выполняем переход Площадка Конфигурация Добавление устройств и нажимаем кнопку Регистрация.



Рисунок 17. Раздел Площадка Конфигурация Добавление устройства.


Появится окно Регистрация по МАС-адресу и серийному номеру. Вводим необходимые параметры.


После ввода серийного номера и MAC Nebula сразу определяет устройство.



Рисунок 18. Окно Регистрация по МАС-адресу и серийному номеру.


Обратите внимание на важное предупреждение на красный символ со значком i:


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


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


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


Ставим галочку Подтверждение и нажимаем OK.


Вновь ведённую точку доступа можно увидеть в разделе Точки доступа Мониторинг Точки доступа.



Рисунок 19. Раздел Точки доступа Мониторинг Точки доступа.


Переходим в раздел Точки доступа Аутентификация. Здесь мы просто выбираем тип аутентификации WPA2 Enterprise.



Рисунок 20. Раздел Точки доступа Мониторинг Точки доступа


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

Нам осталось ввести учётные записи пользователей.


Нам нужен раздел Площадка Конфигурация Облачная аутентификация и далее раздел Пользователи. Нажимаем кнопку Добавить и появляется окно для создания пользователя. На рисунке ниже у нас уже создан пользователь ivan и открыто окно для редактирования реквизитов.



Рисунок 21. Учётная запись пользователя.


Далее снова берём ноутбук и настраиваем доступ к сети.


Windows выводит уже знакомое приглашение ввести логи и пароль.



Рисунок 22. Подключение к WiFi.


Но после ввода появляется ещё одно интересное сообщение:



Рисунок 23. Сообщение о подключении к сети Nebula.


В данном случае нас всё устраивает, поэтому спокойно подключаемся к WiFi сети.


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


Подводя итоги


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


Можно упростить задачу и использовать встроенные решения, как, например, в межсетевом экране USG FLEX. А может быть лучше максимально упростить задачу и просто использовать облачный сервис со всеми удобными функциями? Выбор, как всегда, за конечным потребителем.


Полезные ссылки


  1. Telegram chat Zyxel
  2. Форум по оборудованию Zyxel
  3. Много полезного видео на канале Youtube
  4. Настройка WPA2 Enterprise c RADIUS
  5. Особенности защиты беспроводных и проводных сетей. Часть 1 Прямые меры защиты
  6. Двухдиапазонная точка доступа 802.11ax (WiFi 6) NWA210AX
  7. Межсетевой экран USG FLEX 200
  8. Zyxel ONE Network Utility (ZON)
  9. Zyxel Nebula
Подробнее..

Рамка (граница) окон в windows 10 и server 2016

25.02.2021 18:11:56 | Автор: admin

Наверно я не один такой, кто столкнулся с проблемой отсутствия границ окон в новых системах windows, ведь зачем-то их убрали с одним из обновлений. Спрашивают многие, а вот ответа нет однозначного нигде. С данной неожиданной неприятностью легко справиться, сменив руками настройки системы, а если это терминальный сервер и пользователей много? По умолчанию, пользователям выставляется наилучшее быстродействие, что отключает тени, в придачу по умолчанию в системе отключены границы окон, что приводит к полному сливанию окон друг с другом, в итоге невозможно отличить где кончается одно и начинается другое окно. Когда я решил централизованно решить эту проблему для всех пользователей, оказалось что найти решение не так уж и просто, поскольку нет ни одного ответа в интернете, дающего однозначное решение. В итоге перелопатив весь RU и EN сегменты сети, перепробовав разные варианты, я решил проблему. Если вас беспокоит та же проблема, прошу под кат.

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

Итак, вы имеете ситуацию как на картинке выше. Ваш путь лежит в редактор GPO, где надо сделать манипуляции, согласно следующей картинке:

Добавив данные изменения, требуется перезагрузка. Войдя в систему, появятся рамки и стандартные цвета системы:

В общем-то, на этом все, вы успешно избавились от безрамья и мелкомягкой, весьма странной "фичи".

Подробнее..

Перевод Почему Windows около 20 секунд упорядочивает невидимые значки Рабочего стола?

26.02.2021 10:11:26 | Автор: admin

Что не так с компьютером в нём установлен накопитель nvme, но открытие проводника, если этого давно не делали, занимает примерно 10 секунд, открытие файла .zip на рабочем столе занимает примерно минуту, а при нажатии клавиши Пуск реакции нужно ждать примерно 20 секунд?

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

Фрейя отправила мне трассировку ETW того, что происходит с её машиной и я исследовал её с помощью Windows Performance Analyzer (WPA). Первым делом я заметил, что график UI Delays показывает, как и можно было догадаться, что потоку explorer.exe 7888 не удавалось проверить сообщения в течение 20,531 секунд. Он завис.


У explorer.exe есть много UI-потоков, поэтому это не значит, что повис весь процесс, однако одно из его окон определённо зависло и вызывало зависания повсюду, а это плохо.

Если потоку не удаётся перекачивать сообщения, то это значит, что он или занят чем-то другим (потребляет ресурсы ЦП), или ожидает чего-то другого (ЦП простаивает). Изучив более детально период времени 20,531 секунд MsgCheck Delay, я проверил данные CPU Usage (Precise) (взятые из инструментария переключения контекста) и увидел, что поток 9228 был запущен в течение 99,2% времени он потреблял много ресурсов ЦП.

Далее надо было выяснить, что происходит. Данные CPU Usage (Sampled) (получаемые от профилировщика с сэмплированием 1 кГц) сообщили мне, что поток 9228 тратит примерно 99,7% своего времени (26994 из 27074 сэмплов) в деструкторе BatchPositionChangesHelper (строка 21) и его дочерних задачах (строки 23-25). Это очень затратный деструктор.


У меня нет доступа к этому исходному коду, но я немного поизучал стеки и они намекают, что explorer.exe тратил больше 20 секунд, выполняя множество задач, связанных с выравниванием положения значков.

Ага, именно так


Выстраивание значков на Рабочем столе довольно простая задача. Нужно просто выровнять их в столбцы, перейти к следующему столбцу и завершить работу, когда экраны заполнены. Поэтому 20 секунд на выстраивание значков не показалось мне реалистичным временем, и я предположил, что первопричиной может быть какое-нибудь странное расширение оболочки или другое стороннее ПО, но потом попробовал воспроизвести баг самым простым способом. Я подумал, что просто создам на Рабочем столе тысячу копий крошечного изображения .jpg и проверю, не будет ли explorer.exe тормозить. Этот эксперимент был слишком тупым, чтобы оказаться достаточным, но тем не менее:

src = os.path.join(script_path, SunsetWhales.jpg)dst = os.path.join(desktop_path, TestFiles%04d.jpg)for i in range(file_count):  shutil.copy(src, dst % i)

Я запустил этот простой скрипт со значением file_count, равным 1000, и внезапно explorer.exe начал безумно тормозить более двадцати секунд. Всё действительно оказалось так просто.

Но почему?


Компьютеры сегодня очень быстры. Процессор Фрейи работает с частотой 4,6 ГГц, а на её Рабочем столе находится примерно 950 файлов GIF. За 20 секунд её ЦП должен выполнить 92 миллиарда тактов или по 97 миллионов тактов на каждое изображение. А это много.

Я предположил, что проблема была связана с наблюдением, которое я для себя назвал первым законом вычислений Доусона: O(n^2) оптимальное время для плохо масштабируемых алгоритмов достаточно быстро, чтобы попасть в продакшен, но достаточно медленно, чтобы ломать всё, после того, как он туда попал.

То есть наиболее вероятное объяснение того, почему выстраивание значков занимает так много времени, заключается в том, что код перестроения порядка значков использует O(n^2) (он же квадратичный) алгоритм, то есть при удвоении количества значков время на их выстраивание возрастает в четыре раза. При таком масштабировании производительности алгоритм, хорошо работающий с десятью элементами, может тормозить всего с тысячей элементов.

Хорошая теория, но как её доказать?

Научно!


Я начал с написания скрипта, который заполнит мой Рабочий стол заданным количеством изображений. Я многократно запускал его со всё большими количествами изображений и записал трассировку ETW, чтобы можно было замерить производительность. Также я отслеживал explorer.exe с помощью Диспетчера задач, чтобы можно было понять, когда он закончил одну задачу и готов к следующей.


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

Изучая трассировки, я понял, что деструктор BatchPositionChangesHelper выполнялся бОльшую часть времени (синяя область), но не всё время работы explorer (зелёная область):


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

Когда мой скрипт на Python начинал создавать изображения, процесс explorer.exe замечал это и сразу же начинал пытаться разместить значки. В процессе создания изображений он мог делать это несколько раз, что давало непредсказуемые результаты. Это была ситуация гонки, из-за которой постоянство общих затрат оказывалось нарушенным. Так как у меня не было доступа к исходному коду explorer.exe, мне нужно было придумать способ заставить его ждать завершения создания всех изображений, а потом уже выполнять выстраивание. Я реализовал это с помощью библиотеки psutil, позволившей приостановить процесс explorer.exe, пока создавались изображения. Затем, когда я возобновлял процесс, он проделывал всю работу. Код выглядит примерно так:

explorer = p = psutil.Process(explorer_pid)explorer.suspend()CreateImages()explorer.resume()

Сделав это, я запустил свой тестовый пакетный файл, параллельно записывая трассировку ETW. Для минимизации шума и размера трассировки я отключил стеки вызовов переключения контекста (необязательные) и выключил индексирование папки Рабочего стола. Я отслеживал загрузку ЦП процессом explorer.exe с помощью Диспетчера задач и нажимал на Enter, чтобы перейти к следующему тесту, когда загрузка падала до нуля. Так я получил очень красивый график загрузки ЦП процессом explorer.exe:


Отдельные блоки обозначают загрузку ЦП для 100, 200, 300 и так далее изображений вплоть до 1000. Если вы внимательны, то заметите, что загрузка ЦП увеличивается быстрее, чем линейно, но медленнее, чем квадратично. То есть изначальные данные позволяют предположить, что алгоритм выстраивания не-совсем-O(n^2).

Однако explorer занимается не только выстраиванием. Если некоторые из задач O(n), то есть линейны, то они ослабят влияние задач O(n^2). При увеличении n задачи O(n^2) постепенно начнут доминировать, но я не хотел, чтобы моя тестовая программа работала даже дольше 160 секунд, которых требует её выполнение.

Изолирование


Значит, следующей задачей будет изолирование времени, потраченного на деструктор BatchPositionChangesHelper. В моей тестовой трассировке оно составило 78,4% времени, потраченного в explorer.exe, и 92,3% времени, потраченного в занятом потоке, и если я смогу доказать, что оно было квадратичным, то докажу, что при увеличении n оно будет доминировать навсегда.


Для этого я посмотрел на данные CPU Usage (Sampled) и отфильтровал их, чтобы отображались сэмплы только в деструкторе BatchPositionChangesHelper и его дочерних задачах. Затем я рассмотрел десять разных областей графика и составил график количества сэмплов. Кривая настолько плавная, что выглядит подделкой, но это именно настоящие данные.

Если взглянуть на ключевые точки графика, например, где количество изображений равно 500, а потом 1000, то можно увидеть, что масштабирование производительности происходит немного хуже, чем O(n^2). То есть для выстраивания 1000 значков требуется в четыре с лишним раза больше времени, чем на выстраивание 500 значков.

Решающий удар


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


Фрейя использовала свой Рабочий стол для хранения файлов GIF. Она обращалась с ним, как с папкой (чем он собственно и является), в которой можно удобно хранить изображения. Она редко пользовалась значками с Рабочего стола. Поэтому когда количество значков со временем стало избыточным, она решила снять флажок Show desktop icons (Отображать значки рабочего стола), чтобы было меньше неразберихи. Значки скрылись и она могла продолжать сохранять изображения в эту папку.

Но тем не менее

Испытываемые ею зависания, при которых explorer тратил 20 с лишним секунд на выстраивание значков на Рабочем столе, тратя 92 миллиарда тактов ЦП на правильное размещение значков, происходили тогда, когда значки были скрыты.

Это какой-то новый уровень удивительности.

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

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

Ловушки


Похоже, что этот баг связан с изменением схем использования нескольких мониторов (как мне сказали, такая необходимость часто возникает у стримеров), поэтому какое-то время я проводил тесты, подключая и отключая свой внешний монитор. Это плохо подходит для эффективного тестирования, к тому же, похоже, я испортил разъём для внешнего монитора у своего личного ноутбука. Больше он не видит внешний монитор. Упс.

Да, с символами


Когда я анализировал трассировку Фрейи, я просто загрузил её в Windows Performance Analyzer (WPA) и подождал. Мне не нужно было проверять версию Windows, на которой она работала, и знать, какие патчи у неё установлены. WPA просто изучал отладочную информацию всех EXE и файлов PE и скачивал файлы символов с серверов символов Microsoft (и с серверов Chrome, потому что я это разрешил). Серверы символов это хорошо. Если вы работаете в Windows, то включите использование серверов символов. Если вы не в Windows, то сильно вам сочувствую (жаль, что отладка и профилирование, особенно проблем на машинах других пользователей, для вас гораздо сложнее).

Сообщаем о проблеме


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

Сырые измерения из моих тестов сохранены здесь, а сами тесты находятся на github. Этот баг чрезвычайно легко воспроизвести. Если кто-то захочет создать запись Feedback Hub, то это нужно сделать. Рекомендую при зависании Рабочего стола использовать опцию UIforETW Browse Folder операция будет заблокирована на всё время зависания.

Уроки для разработчиков ПО


За свою карьеру я много раз участвовал в собеседованиях. Часто мне давали задание придумать алгоритм, выполняющий какую-то искусственную задачу. Очевидный алгоритм грубого перебора обычно оказывается квадратичным (O(n^2)) или реже экспоненциальным (O(2^n)). Чаще всего это приводит к обсуждению следующих тем:

  1. Почему квадратичные и экспоненциальные алгоритмы неприемлемо медленны для большинства задач реального мира
  2. Как усовершенствовать алгоритм, чтобы он был O(n log n) или лучше.

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



На правах рекламы


Эпичные серверы это виртуальные серверы на Linux или Windows с мощными процессорами семейства AMD EPYC и очень быстрой файловой системой, используем исключительно NVMe диски от Intel. Попробуйте как можно быстрее!

Подробнее..

Как ленивый работящему помог. Ещё один скрипт для релиза подкаста

27.02.2021 10:19:52 | Автор: admin
Было время, когда у меня уже были дети, стабильная работа, камри, уроки английского и три раза в неделю бассейн. В общем такой себе состоявшийся мужчина. И я размышлял "Ну зачем мне питон? На работе совсем нет задач для автоматизации". Ни единого раза с того момента я не оказывался на столь высоком пике Даннинга-Крюгера (брата Баадера-Майнхофа, если что).
Но на курсы я тогда всё же сходил.
С тех пор прошли годы, число детей выросло, работу поменял, бассейн бросил, а автоматизирую теперь всё, до чего дотягиваются беспокойные руки.

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




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

Ведь как выглядит релиз видео:
1. Собрать в фигме обложку подкаста.
2. Собрать в одном месте обложку, mp3 и запустить рендер в ffmpeg
3. Вручную залить готовое видео на ютуб
4. Заполнить название, описание, теги, дать ссылку на пост на сайте, добавить в нужный плейлист.
5. Опубликовать в день релиза

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

И я подумал, почему бы не помочь товарищу дружеским скриптом, который соберёт всё в одном месте в удобном виде.
Примерно таком.
Жисон:
{    "kdpv": "https://fs.linkmeup.ru/images/podcasts/linkmeup-V089(2020-07).jpg",    "link": "https://linkmeup.ru/blog/571.html",    "podcast_url": "https://dts.podtrac.com/redirect.mp3/https://fs.linkmeup.ru/podcasts/telecom/linkmeup-V089(2020-07).mp3",    "title": "telecom 89. Транспорт и управление перегрузками",    "body": "Some body that I used to know"}


Хотя бы копировать из одного места, и картинка вот она уже подспорье.





XML to DICT


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

Так появился get_podcasts.py.
Всё что он делал: собирал в один словарь title, podcast_url, body и kdpv. В качестве последнего он брал первый попавшийся img src, если им была не картинка с патреон.
Словарь пишется в файл all_podcasts.json.



REQUESTS a file


Следующая светлая мысль, обещающая непыльную работу и драматическое упрощение труда энтузиаста, не заставила себя ждать:
Ну когда уже URL есть, почему бы файлики не скачать и не положить рядышком?

Так появился download_podcasts.py, который скачивал звук и изображение, выделял им случайное имя, сохранял в соответствующих директориях, и обогащал словарь all_podcasts этими именами, сохраняя результат в all_podcasts_w_files.json.

И тут же ещё категорию подкаста укажем.
Жисон:
{    "category": "telecom",    "img": "img/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.jpg",    "kdpv": "https://fs.linkmeup.ru/images/podcasts/linkmeup-V089(2020-07).jpg",    "link": "https://linkmeup.ru/blog/571.html",    "mp3": "mp3/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp3",    "podcast_url": "https://dts.podtrac.com/redirect.mp3/https://fs.linkmeup.ru/podcasts/telecom/linkmeup-V089(2020-07).mp3",    "title": "telecom 89. Транспорт и управление перегрузками",    "body": "Some body that I used to know"}


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




И вот казалось бы всё бери ffmpeg двумя руками на полчасика в день и ты чуть ближе к счастью.

Ну вот ещё командочку сгенерю, чтобы уж совсем просто было вставлять.
ffmpeg -loop 1 -i "img/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.jpg" -i "mp3/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp3" -c:a copy -c:v libx264 -shortest "mp4/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp4"

"Постой" скажет практикующий скриптинг читатель "Ну ты же ленивый, но не настолько глупый запусти команду через subprocess".

Ну вот и я так подумал. И отсюда начинается захватывающая дух история.



Enter SUBPROCESS


"Только Hello world может быть проще, чем запустить команду linux из питона" считал я на основе своего более чем скромного опыта. Импорт сабпроцесс, сабпроцесс.попен и погнали.
Но засада оказалась там, где её не ждали: ffmpeg отдавал какой-то код возврата питону, а сам продолжал считать в фоне. Питон же считал, что команда отработала, и исполнял дальше. А дальше цикл по всем эпизодам.
При первом же запуске окно терминала превратилось в какую-то манку с комочками. Я подозреваю, что наши 200 подкастов даже отрендерелись бы за какой-то необозримый промежуток времени.

Но такой жгучий дискомфорт я почувствовал в области органа тотального контроля, что пришлось стопнуть и поставить input(). Чего уж там 200 раз нажать на энтер мне не сложно.
render_video.py

И я запустил РЕНДЕР. Ноутбук зашуршал вентиляторами, пытаясь остудить горячее своё нутро. На следующие несколько суток этот звук стал верным моим спутником.
Он считал видео и обогащал all_podcasts_w_mp4.json именем файла mp4.
Жисон:
{    "category": "telecom",    "img": "img/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.jpg",    "kdpv": "https://fs.linkmeup.ru/images/podcasts/linkmeup-V089(2020-07).jpg",    "link": "https://linkmeup.ru/blog/571.html",    "mp3": "mp3/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp3",    "mp4": "mp4/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp4",    "podcast_url": "https://dts.podtrac.com/redirect.mp3/https://fs.linkmeup.ru/podcasts/telecom/linkmeup-V089(2020-07).mp3",    "title": "telecom 89. Транспорт и управление перегрузками",    "body": "Some body that I used to know"}

Но тут наступила ночь время, когда я обычно не нажимаю на клавишу энтер. Но нельзя ведь терять столько драгоценное время поэтому меняем input() на time.sleep(1800) за полчаса должно же посчитаться.

Добавил условие, что рендерить видео нужно, только если mp4 в словаре ещё отсутствует, и ушёл спать.

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

За это время я научился по звенящей тишине определять, что пора нажимать энтер и запускать расчёт дальше.
Я настолько привык к этому фоновому шуму, отсылавшему меня назад в нулевые, когда на ЭЛТ-мониторе NFS Porsche Unleashed сменял Max Payne, а в ногах шумел неистово биг-тауэр c селероном, что весь день, когда последний эпизод отрендерился, и в комнате повисла зловещая тишина, мне навязчиво казалось, что что-то вышло из строя.

К этому моменту у меня были директории с mp3, img, mp4, и заполненный файлик all_podcast_w_mp4.json со всеми необходимыми ссылками.



pip install --upgrade google-api-python-client


Но вместо заслуженного отдыха я уже 2 дня к этому моменту изучал YouTube Data API.

Самый поверхностный гуглёжь навёл на готовый скрипт на питон2 upload_video.py, который можно запустить с ограниченным списком аргументов.

python upload_video.py --file="/tmp/test_video_file.flv"                       --title="Summer vacation in California"                       --description="Had fun surfing in Santa Cruz"                       --keywords="surfing,Santa Cruz"                       --category="22"                       --privacyStatus="private"


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

И мы подумали, что будем загружать все видосы в скрытом режиме и публиковать раз в месяц все эпизоды одного года.
Поэтому появился скрипт get_pub_dates.py, который ещё раз парсит RSS и собирает из него даты публикации эпизода на сайте, которые затем транслируются в запланированную дату публикации на ютубе.
Жисон:
{    "category": "telecom",    "img": "img/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.jpg",    "kdpv": "https://fs.linkmeup.ru/images/podcasts/linkmeup-V089(2020-07).jpg",    "link": "https://linkmeup.ru/blog/571.html",    "mp3": "mp3/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp3",    "mp4": "mp4/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp4",    "podcast_url": "https://dts.podtrac.com/redirect.mp3/https://fs.linkmeup.ru/podcasts/telecom/linkmeup-V089(2020-07).mp3",    "publishAt": "2021-09-30T12:00:03.000Z",    "recordingDate": "2020-07-25T08:25:14.000Z",    "title": "telecom 89. Транспорт и управление перегрузками",    "body": "Some body that I used to know"}

all_podcasts_w_pd.json

И вот готов скриптецкий, заливающий килотонны видео в наш доселе камерный канал: upload_video.py (на python3).

И вот что получилось.
Жисон:
{    "category": "telecom",    "img": "img/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.jpg",    "kdpv": "https://fs.linkmeup.ru/images/podcasts/linkmeup-V089(2020-07).jpg",    "link": "https://linkmeup.ru/blog/571.html",    "mp3": "mp3/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp3",    "mp4": "mp4/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp4",    "podcast_url": "https://dts.podtrac.com/redirect.mp3/https://fs.linkmeup.ru/podcasts/telecom/linkmeup-V089(2020-07).mp3",    "publishAt": "2021-09-30T12:00:03.000Z",    "recordingDate": "2020-07-25T08:25:14.000Z",    "title": "telecom 89. Транспорт и управление перегрузками",    "youtube_id": "jFvFIpWDjKM",    "body": "Some body that I used to know"}


Кстати, пользуясь случаем, шлю лучи добра в корпорацию зла за дружелюбные интерфейсы. Более удобных мест и способов получения ключей я нигде не видел. Получил качественное эстетическое удовольствие.
Ну и ещё, чтобы вы поняли, насколько вам хорошо живётся, если не приходится использовать YouTube API:
Нельзя добавить видео в плейлист, если он остортирован по дате добавления.
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&alt=json returned "Playlist should use manual sorting to support position.". Details: "Playlist should use manual sorting to support position.">

Зато если уж можно, то добавить можно хоть 1000 раз одно и то же видео.
Если видео добавлены в плейлисты, то в админке они исчезают с главной (а у обычного пользователя нет).
Официальные видео по IAM и документация к API не совсем соответствует действительности.


К слову, каждый сеанс связи с гугл-АПИ авторизуется отдельно. Вам выдаётся ссылка, на которую нужно тыкнуть, а потом в интерфейсе тыкнуть ещё 6 (6, НАТАША!!!) раз, чтобы получить код авторизации. Действует он только на этот запуск скрипта, потом нужно получать новый.
Я читал, что есть некий REFRESH Token, который не протухает, но, спасибо интерфейсам, я так и не постиг мрачную тайну его использования.
Ещё у ютуба, оказалось, имеется квота на количество операций по API. 10 000 енотов в день.
И прайс такой: загрузка видео 1600 за каждую попытку, обновление плейлиста 50. Узнал я об этом после 6-го видео. Весь список, пожалуйста.
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://youtube.googleapis.com/upload/youtube/v3/videos?part=snippet%2Cstatus%2CrecordingDetails&alt=json&uploadType=multipart returned "The request cannot be completed because you have exceeded your <a href="http://personeltest.ru/aways/habr.com/youtube/v3/getting-started#quota">quota</a>.". Details: "The request cannot be completed because you have exceeded your <a href="http://personeltest.ru/aways/habr.com/youtube/v3/getting-started#quota">quota</a>.">

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



Мне потребовалось время, чтобы смириться с мыслью, что трое суток рендера и мучений моего ноутбука были напрасны. Что 200 моих детищ ждёт /dev/null с распростёртыми файл-дескрипторам. И их нужно будет в муках рожать заново.
Но!



ImageDraw.Draw


Воистину большим препятствием была лень рисовать обложки. Их же не 1 и не 2 их 200!
Шаблон обложки у нас лежит в фигме. И набор действий для создания оной под каждый эпизод в целом механический.
"Ну наверняка есть API у фигмы, через который можно проделать те же манипуляции" опять подумал я (всё же, похоже, что думать это не моё). Цена тому научиться в ещё один API. Что? мало разве их было в моей грешной жизни?
Увы, API фигмы Read Only надежды рассыпались.
Мы сели с нашим дизайнером и начали думать что же можно поделать. Он сказал, что может написать веб-сервис, который нам такую картинку сгенерит. И после мгновения радости от найденного решения, сразу в голову полезли мысли о том, что его нужно где-то разворачивать, поддерживать, мониторить чуть больше головняка, чем хотелось бы. Но эта идея склонила мою мысль на подушку, в смысле Pillow форк библиотеки PIL (Python Imaging Library) для работы с изображениями. Там вообще чудеса можно творить и на голове стоять.

Всё, что было нужно сделать:
Иметь два изображения: шаблон обложки и картинку эпизода.
Отресайзить последнюю и обрезать до нужного размера
Скруглить ей углы
Наложить её на шаблон обложки
Добавить текст с названием эпизода.



Делов-то: сесть и сделать.
Думал я так, и это даже оказалось недалеко от истины дело техники.
И опыта, которого у меня не было. Я с удивлением для себя открыл, как работает прозрачность в png. Я около часа боролся с этой квадратурой круга: все углы у изображения скруглил, а оно вставляется в шаблон обложки ровным прямоугольником. Я уже проверял из каких файлов берутся эти изображения, пробовал другие, сохранял картинку со скруглёнными углами в файл, чтобы проверить, что они действительно скруглены. Я даже сам в гимпе нарисовал пнг с большим прозрачным пятном посередине. Но чертовщина продолжалась.
Пока не пришло просветление, что прозрачность задаётся маской поверх полного изображения, а Image.paste по умолчанию это дело игнорирует (или не умеет работать).
В итоге нужно было маску извлечь из изображения и накладывать с её учётом. Фьюх.

r, g, b, m = img.split()top = Image.merge("RGB", (r, g, b))mask = Image.merge("L", (m,))cover.paste(top, (44,83), mask)




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

if len(text) < 50:    letters = 17elif len(text) < 80:    letters = 21else:    letters = 26text = ''row = ''for word in words:    if len(row+word)+1 <= letters:         row += f'{word} '        text += f'{word} '    else:        row += f'\n{word} '        text += f'\n{word} '        row = word




Полный код скрипта: gen_kdpv.py.
Жисон:
{    "category": "telecom",    "cover": "img/covers/afc5a3cf-cbcf-4c3f-8a64-9cc8df589ba3.png",    "img": "img/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.jpg",    "kdpv": "https://fs.linkmeup.ru/images/podcasts/linkmeup-V089(2020-07).jpg",    "link": "https://linkmeup.ru/blog/571.html",    "mp3": "mp3/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp3",    "mp4": "mp4/ef684cbd-9fb0-4226-8a8c-b1c6ff4ae908.mp4",    "podcast_url": "https://dts.podtrac.com/redirect.mp3/https://fs.linkmeup.ru/podcasts/telecom/linkmeup-V089(2020-07).mp3",    "publishAt": "2021-09-30T12:00:03.000Z",    "recordingDate": "2020-07-25T08:25:14.000Z",    "title": "telecom 89. Транспорт и управление перегрузками",    "youtube_id": "jFvFIpWDjKM",    "body": "Some body that I used to know"}





While True


Я пожалел своего Боливара и решил воспользоваться виртуалочкой, любезно запущенной моим соратником на производственных мощностях linkmeup.
Но для этого нужно было решить один вопрос как не нажимать на проклятый энтер. Не то чтобы это было невозможно на вируталке или я смертельно устал. Нет! Это был уже вопрос моей чести как скриптоинвестора нельзя было после такой работы идти на компромиссы.

Для питона, конечно же, есть батарейка с ffmpeg. Этому я даже не удивился, я шёл на stackoverflow в поисках именно её.

Вообще пусть славятся в веках имена создателей stackoverflow, которые обеспечили бутерброд с икрой таким как я!


Но как-то то ли контакта на батарейке не два, то ли я просто не догадался, какой стороной её вставлять. Одним словом переложить знакомые команды даже после обращения к более опытным в питоне товарищам, не получилось.
И тут элегантное, как валенки, решение осветило внутреннюю поверхность черепа. Subprocess, наверняка, возвращает ID процесса. А что если просто дождаться его завершения, прежде чем выполнять код дальше?
И вот это озарило своим присутствием мой скрипт:

while True:    if psutil.Process(run_cmd.pid).status() == 'zombie':        break

render_video_norm.py

После этого я со спокойной душой залил всё это барахло на виртуалочку, в tmux'е запустил скрипт и ушёл писать этот пост на следующие 5 дней.
Единственное, что оставалось ручного это каждый день запускать скрипт загрузки видосов, потому что квота, и потому что сессионные ключи.
Однако довольно быстро была найдена секретная форма с заявкой на расширение квоты.
Сделана она прицельно так, чтобы ты дошёл до её конца, только если у тебя действительно очень острая необходимость квоту увеличить.
Без какой-либо надежды я заполнил эту форму минут за 20, расписав каждого необходимого мне енота, и без надежды ушёл спать. 14 раз. А через 2 недели мне пришло письмо счастья от гугла, где моя квота была повышена до 350000. И далее за один день я уже залил всё, что хотел.



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




Продакшон реди


Ну и апофеозом всей этой волнительной истории должен стать готовый продукт для релиза новых подкастов. Ведь мы же не прекращаем ртом в микрофон говорить. А для продукта уже почти всё готово.

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

Теперь, чтобы зарелизить подкаст, надо (кроме его записи и обработки, конечно же):
Найти картинку к выпуску, придумать название и подготовить описание.
А дальше:
./release.py -i 'img/test.jpg' -m 'mp3/test.mp3' -t 'telecom 196. Лист и феоктист' -d description.html


И оно само:
  • Нарисует обложку для ютуб,
  • отмасштабирует в обложку для RSS и для ВК,
  • зальёт все файлы на хостинг
  • Отрендерит видео
  • Зальёт его на ютуб с описанием в нужный плейлист
  • Подготовит текст для поста на сайт


Последнее это временная полумера, пока мы не переедем на ипси-дипси новый сайт на вордпрессе с адекватным REST API.
И в целом останется только вопрос кросспостинга его в вк, телегу и менее привлекательные каналы.

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

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

Блеск и нищета Virtual Tape Library

02.03.2021 10:09:04 | Автор: admin

VTL (они же Virtual Tape Library, если по паспорту) можно назвать одним из самых странных порождений IT индустрии. Родившись в эпоху расцвета ленточных накопителей как классический софтовый эмулятор настоящего железа, многими они были восприняты как ответ на главный вопрос жизни (Вселенной и всего такого), и теперь одни умудряются продавать их за деньги, а другие использовать в проде и считать, что всё нормально.

Я не буду кричать что первые плохие, а вторых надо гнать из профессии. Нет. Я только лишь предлагаю трезво взглянуть на суть VTL.

А в чём проблема?

Чтобы разобраться с вопросом о легитимности использовании VTL, давайте вспомним, зачем вообще нужны ленты. Это самое дешёвое, не самое быстрое, зато физически отчуждаемое устройство для хранения информации. Про дешевизну можем говорить, если посчитаем цену условного терабайта хранения. Прямо сейчас LTO-8 лента в режиме сжатия способна принять на себя 30 Терабайт данных, при цене около 9000 рублей. Для объективности можно даже откинуть маркетологов с их сжатием и записать только честные, физически наносимые 12,8 Тб. Для сравнения, за те же деньги можно взять SSD на один терабайт или обычный HDD на четыре. А тут сразу 12,8. Или даже 30, если повезёт. Да, для ленты ещё нужен привод, а лучше даже библиотека с роботом ценой в несколько сотен тысяч рублей, но там, где есть приличные объёмы данных, для которых встаёт вопрос о хранении на протяжении многих лет, это всё-таки дешевле, чем закупать дисковые полки и заниматься их обслуживанием.

Но из-за своей природы (пластиковая лента с магнитным слоем) у лент есть несколько очень неприятных моментов. Например, на ленту можно не слишком быстро писать данные, а потом очень долго и медленно их считывать. Особенно если речь идёт о файлике, который физически оказался в самом конце вашей кассеты. Пока вы будете ждать перемотки ленты на необходимое место, тут даже HDD с его задержками на раскрутку шпинделя и необходимостью двигать коромысло со считывающей головкой покажется манной небесной. Другая ленточная беда - невозможность изменять файлы. Файл, записанный на ленту, можно только удалить. Изменили полтора байта в вашем файле? Добро пожаловать в конец дорожки, кажется, там ещё оставалось место, чтобы перезаписать весь файл ещё раз.

И, конечно же, помним про возможность простого физического отключения. Вставили ленту в привод, записали на неё что-то, привод ленту выдал обратно, вы её убрали подальше, и голова ваша не болит. Лента лежит, собирает пыль, и ничего с ней не происходит. Диски так не умеют. Даже если и хочется вынуть диск сервера и убрать на полку, то придётся разбирать корпус и вырубать весь сервер. Если это дисковая полка, то корпус разбирать не придётся, но насиловать не рассчитанные на постоянное туда-сюда разъёмы тоже не очень хочется. А вот лентам для счастья ничего не надо. Ни электричества, чтобы постоянно крутить шпиндель, ни страха перед разболтавшимися разъёмами.

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

Все эти прекрасные особенности давно заприметили разного рода регулирующие гос.органы примерно всех стран. Если вы не знали, то есть довольно много компаний, от которых на законодательном уровне требуется хранить разного рода информацию по многу лет. Спросите, например, медиков, банки, страховщиков и так далее. Вам могут рассказать массу увлекательных историй про то, как они вынуждены обеспечивать сохранность данных своих клиентов на протяжении лет десяти-пятнадцати. Вы же не думаете, что кто-то в здравом уме будет покупать дисковую полку, задача которой будет заключаться в простаивании 99% времени? Да и диски придётся поменять не один раз за эти десять лет. Поэтому не только зарегулированные, но и обычные компании, где решили заняться архивным хранением, давно пришли к выводу, что ленты и только ленты.

Но есть тут один нюанс, который объяснит нам причины появления VTL почти тридцать лет назад. Представьте, что ваше основное боевое хранилище это дорогущий SAN, сделанный с использованием самых последних технологий своего времени. И вдруг выясняется, что к этому FiberChanel монстру надо подключить ленточную библиотеку по страшному и медленному SCSI интерфейсу. Полученная скорость работы вызовет у вас депрессию, не извольте сомневаться. И вот, после недельного запоя у вас появляется светлая мысль: А может ну их, эти ленты?. Но потом вы вспоминаете, что это Ну их может стоить многих денег вашей компании в виде штрафов от регулятора. Ну и весёлых приключений лично вам, если звёзды сойдутся особенно удачно. Поэтому у вас рождается очень хитрый план: а давайте вместо лент мы будем использовать всё те же диски, а чтобы рисовать красивые отчёты, мы напишем эмулятор, который будет подключаться к нашему софту, отвечающему за резервные копии, и будет тщательно кивать головой на все его команды к лентам.

И на тот момент это сработало. Появились эмуляторы, функциональность которых находилась на уровне архиватора: упаковать файлы в свой формат и радостно отчитаться по SCSI (или любому другому) порту о том, что ленточка старательно записана, робот её вынул и даже положил вот в такой вот слот в своей библиотеке. Самое натуральное переливание из пустого в порожнее под флагом имитации бурной деятельности. Но дабы не только ругать VTL на чём свет стоит, стоит всё же упомянуть и про их плюсы. Самый главный, действительно, это всё ещё скорость. Если вам совсем некуда девать деньги и ваш VTL пишет свои файлы на SSD, то вы победитель по жизни. Но если с деньгами не настолько всё хорошо, а весь фронт работ это записать буквально десяток плёнок, то диски будут дешевле, как ни крути. Если не верите, то просто посмотрите, сколько стоят современные LTO приводы. Ну и вишенка на торте - нет необходимости перематывать кассету на нужное место. Читай сразу откуда хочешь.

Поэтому главное что хочется сказать - не обманитесь заманчивыми плюсами VTL. Буква V значит Virtual, а все преимущества(и недостатки) лент исходят из их физической природы. Так что VTL может принести вам только моральное удовлетворение, но никак не решить задачу недорогого хранения отчуждаемых бекапов на случай аварии. Да и смысл интеграции с бекапным софтом уже давно пропал из-за наличия встроенных функций для перекладывания бекапов из одной корзины в другую. Например, в Veeam эта функция называется Backup Copy. Пользуйтесь на здоровье.

Да, есть ещё так называемые D2D2T системы, где VTL используется в виде кеша, а потом готовые файлы просто записываются на ленты. Правда, сейчас их будет правильнее называть D2D2C, где C это Cloud.

Препарируем VTL

Ну ладно, раз VTL это идеальная лаба, чтобы ознакомиться с функционалом ленточного бекапа, давайте таки развернём эту лабу и попробуем записать наши бекапы на ленту, хоть и виртуальную. Я долго выбирал между более хардкорным MHvtl и QUADstor с его симпатичным GUI, но в итоге остановился на втором исключительно из-за большей его популярности. Хотя оба проекта бесплатные и обеспечивают плюс-минус одни и те же функции. А производить все манипуляции я буду на CentOS.

Первым делом, конечно же, yum update && yum upgrade и ставим все необходимые пакеты:

yum install httpd gcc perl sg3_utils kernel-devel

Наверняка большая часть этих пакетов и так уже стоит, но вдруг вы такой же маньяк и начинаете с CentOS minimal. Также рекомендуется проверить, что установленные версии ядра и тулзов совпадают, а то в наших планах QUADstor компилировать, и лишние проблемы нам ни к чему. Так что сравниваем выводы uname -r и rpm -qa | grep kernel-devel

[root@centos ~]# uname -r3.10.0-1160.15.2.el7.x86_64[root@centos ~]# rpm -qa | grep kernel-develkernel-devel-3.10.0-1160.15.2.el7.x86_64

Если у вас циферки разошлись, то спасаемся yum upgrade kernel и ребутом.

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

wget https://quadstor.com/vtldownloads/quadstor-vtl-ext-3.0.51-rhel.x86_64.rpm

Теперь идём в директорию, куда скачался файл (если она у вас не стандартная), и устанавливаем пакет. Внимание: я это делают в чисто лабораторных целях и условиях, поэтому поэтому могу себе позволить делать всё от рута. А вы нет! Делайте все с правами рядового пользователя.

rpm -ivh quadstor.rpm

На что я получил отлуп по зависимостям (ох уж эти CentOS minimal)

rpm -ivh quadstor.rpmerror: Failed dependencies:libcrypto.so.10()(64bit) is needed by quadstor-vtl-ext-3.0.51-rhel.x86_64libcrypto.so.10(libcrypto.so.10)(64bit) is needed by quadstor-vtl-ext-3.0.51-rhel.x86_64libssl.so.10()(64bit) is needed by quadstor-vtl-ext-3.0.51-rhel.x86_64

Ладно, мы не гордые, идём и ставим compat-openssl10, так как это всё его библиотеки. И повторяем установку, которая в этот раз завершается успехом за пару минут, и мы становимся обладателями QUADstor, mini PostgreSQL сервера, где будут храниться данные конфигурации, и небольшого Apache Web Server для Web-GUI. Хотя никто не запрещает и дальше всё делать через консоль, но мы пойдём по более наглядному пути. Только перед этим нам надо запустить веб сервер и проверить, запустился ли демон VTL.

systemctl enable httpdservice httpd start/etc/rc.d/init.d/quadstorvtl start

Также установщик вас предупредит, что если хочется работать по FC, то надо обязательно перезагрузиться для корректной установки драйверов. Но в наши планы входит исключительно iSCSI, так что храним аптайм. На этом с консолью действительно всё, и мы можем открывать в любимом браузере WebGUI по IP нашей машины.

Первым делом надо зайти в Physical Storage и выбрать диски для работы. По умолчанию QUADstor выбирает первый диск, который обнаруживает. Читай, диск с системой. У меня на скриншоте виден второй диск, подключённый к этой виртуалке, так что смело выбираю его кнопкой Add.

Сразу предложат добавить этот диск в один из Storage Poolов, которые надо создать заранее. Это некая логическая единица для смыслового объединения лент по какому-то признаку. Как видите, ничего супер-необычного здесь нет, весь джентльменский набор: дедупликация для экономии места, WORM кассеты и репликация кассет. Но нам сейчас это всё не так интересно, поэтому ограничимся стандартным пулом.

Но самое интересное находится в секции Virtual Libraries. Здесь мы выбираем, хозяина какой именно железки мы будем из себя изображать. А то и нескольких сразу, ведь кто нам запретит? Так уж сложилось, что душой я за HP, поэтому хотел выбрать себе HP MSL 6000 с двумя приводами Ultrium 6250, но потом передумал и для наглядности выбрал ветерана ленточных боев - ESL 9000.

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

На этом с настройкой VTL всё, и хочется перейти в интерфейс Veeam, дабы скрестить его с библиотекой. Однако мы не ищем лёгких путёй и подключим библиотеку к другой Windows машине, которая будет работать у нас в качестве Tape Server. Для чего заходим на этот сервер, запускаем iSCSI сервис и iSCSI инициатор. Там находим нашу библиотеку любым из доступных способов и подключаемся к ней. По умолчанию будет использоваться порт 3260, так что может потребоваться добавить соответствующее правило на вашем фаерволе.

Тут наступает важный момент: надо обязательно открыть Device Manager и посмотреть как определились новые устройства. Крайне рекомендуется поставить драйвера, чтобы избежать проблем при работе с библиотекой. Veeam использует стандартные системные вызовы, поэтому если система может работать с библиотекой, Veeam тоже будет работать. А нет драйверов - нет мультиков. Так что если у вас старьё вроде того, что я добавил в свою лабу, система сама всё поставит. Если что-то новое, то качайте с сайта производителя. Технически, Veeam может работать и с универсальным Microsoft Tape Format (MTF), но оригинальные драйвера всегда в приоритете.

И теперь (наконец-то) можно идти на сервер Veeam и открывать вкладку Tape Infrastructure. Где первым делом запустим мастер добавления Tape Server.

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

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

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

Но мы отвлеклись, так что давайте вернёмся в Veeam и проверим, что всё добавилось верно.

Как мы видим на скриншоте, библиотека определилась верная, приводы на месте, а количество кассет совпадает с заданным. Все кассеты находятся в медиа пуле Free, так как мы провели инвентаризацию. Если её пропустить, то все неизвестные ленты попадут в пул Unrecognized. Можно принимать поздравления, ибо всё действительно работает как и должно.

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

Итак, запускаем мастер Backup to Tape, задаём имя джобе и на втором шаге добавляем бекап, который хотим хранить на ленте. Технически можно добавить не просто бекап, а хоть целый репозиторий с бекапами, но мы такого делать не будем. Просто берём один красивый бекапчик.

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

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


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

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

Ну а почему бы и нет? Имею право на мечты! Разве не для этого были придуманы VTL решения?

И на последок, ловите ссылку на раздел документации посвящённый работе с ленточными девайсами. Скорее всего там вы найдёте ответы на все свои вопросы.

Подробнее..

Категории

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

© 2006-2021, personeltest.ru