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

Мир plat.form

Recovery mode От стартапа до тысяч серверов в десятке ЦОД. Как мы гнались за ростом Linux инфраструктуры

03.07.2020 20:16:17 | Автор: admin
Если ваша IT инфраструктура растёт слишком быстро, вы рано или поздно столкнётесь с выбором линейно увеличивать людские ресурсы на её поддержку или начинать автоматизацию. До какого-то момента мы жили в первой парадигме, а потом начался долгий путь к Infrastructure-as-Code.



Разумеется, НСПК не стартап, но такая атмосфера царила в компании в первые годы существования, и это были очень интересные годы. Меня зовут Корняков Дмитрий, более 10 лет я поддерживаю инфраструктуру Linux с высокими требованиями доступности. К команде НСПК присоединился в январе 2016 года и, к сожалению, не застал самого начала существования компании, но пришел на этапе больших изменений.

В целом, можно сказать, что наша команда поставляет для компании 2 продукта. Первый это инфраструктура. Почта должна ходить, DNS работать, а контроллеры домена пускать вас на сервера, которые не должны падать. IT ландшафт компании огромен! Это business&mission critical системы, требования по доступности некоторых 99,999. Второй продукт сами сервера, физические и виртуальные. За существующими нужно следить, а новые регулярно поставлять заказчикам из множества подразделений. В этой статье я хочу сделать акцент на том, как мы развивали инфраструктуру, которая отвечает за жизненный цикл серверов.

Начало пути

В начале пути наш стек технологий выглядел так:
ОС CentOS 7
Контроллеры домена FreeIPA
Автоматизация Ansible(+Tower), Cobbler


Всё это располагалось в 3х доменах, размазанных на нескольких ЦОДах. В одном ЦОД офисные системы и тестовые полигоны, в остальных ПРОД.

Создание серверов в какой-то момент выглядело так:



В шаблоне VM CentOS minimal и необходимый минимум вроде корректного /etc/resolv.conf, остальное приезжает через Ansible.

CMDB Excel.

Если сервер физический, то вместо копирования виртуальной машины на него устанавливалась ОС с помощью Cobbler в конфиг Cobbler добавляются MAC адреса целевого сервера, сервер по DHCP получает IP адрес, а дальше наливается ОС.

Поначалу мы даже пытались делать какой-то configuration management в Cobbler. Но со временем это стало приносить проблемы с переносимостью конфигураций как в другие ЦОД, так и в Ansible код для подготовки VM.

Ansible в то время многие из нас воспринимали как удобное расширение Bash и не скупились на конструкции с использованием shell, sed. В общем Bashsible. Это в итоге приводило к тому, что, если плейбук по какой-либо причине не отрабатывал на сервере, проще было удалить сервер, поправить плейбук и прокатить заново. Никакого версионирования скриптов по сути не было, переносимости конфигураций тоже.

Например, мы захотели изменить какой-то конфиг на всех серверах:

  1. Изменяем конфигурацию на существующих серверах в логическом сегменте/ЦОД. Иногда не за один день требования к доступности и закон больших чисел не позволяет применять все изменения разом. А некоторые изменения потенциально деструктивны и требуют перезапуск чего-либо от служб до самой ОС.
  2. Исправляем в Ansible
  3. Исправляем в Cobbler
  4. Повторяем N раз для каждого логического сегмента/ЦОД

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

  • Рефакторинг ansible кода, конфигурационных файлов
  • Изменение внутренних best practice
  • Изменения по итогам разбора инцидентов/аварий
  • Изменение стандартов безопасности, как внутренних, так и внешних. Например, PCI DSS каждый год дополняется новыми требованиями

Рост инфраструктуры и начало пути

Количество серверов/логических доменов/ЦОД росло, а с ними количество ошибок в конфигурациях. В какой-то момент мы пришли к трём направлениям, в сторону которых нужно развивать configuration management:

  1. Автоматизация. Насколько возможно, нужно избегать человеческого фактора в повторяющихся операциях.
  2. Повторяемость. Управлять инфраструктурой намного проще, когда она предсказуема. Конфигурация серверов и инструментов для их подготовки должна быть везде одинаковой. Это так же важно для продуктовых команд приложение должно гарантированно после тестирования попадать в продуктивную среду, настроенную аналогично тестовой.
  3. Простота и прозрачность внесения изменений в configuration management.

Осталось добавить пару инструментов.

В качестве хранилища кода мы выбрали GitLab CE, не в последнюю очередь за наличие встроенных модулей CI/CD.

Хранилище секретов Hashicorp Vault, в т.ч. за прекрасное API.

Тестирование конфигураций и ansible ролей Molecule+Testinfra. Тесты идут намного быстрее, если подключаете к ansible mitogen. Параллельно мы начали писать собственную CMDB и оркестратор для автоматического деплоя (на картинке над Cobbler), но это уже совсем другая история, о которой в будущем расскажет мой коллега и главный разработчик этих систем.

Наш выбор:

Molecule + Testinfra
Ansible + Tower + AWX
Мир Серверов + DITNET(Собственная разработка)
Cobbler
Gitlab + GitLab runner
Hashicorp Vault




Кстати про ansible роли. Сначала она была одна, после нескольких рефакторингов их стало 17. Категорически рекомендую разбивать монолит на идемпотентные роли, которые можно потом запускать отдельно, дополнительно можно добавить теги. Мы роли разбили по функционалу network, logging, packages, hardware, molecule etc. А вообще, придерживались стратегии ниже. Не настаиваю на том, что это истина в единственной инстанции, но у нас сработало.

  • Копирование серверов из золотого образа зло!

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

    1. Оставьте /etc/sysctl.conf пустым, настройки должны лежать только в /etc/sysctl.d/. Ваш дефолт в один файл, кастом для приложения в другой.
    2. Используйте override файлы для редактирования systemd юнитов.
  • Шаблонизируйте все конфиги и подкладывайте целиком, по возможности никаких sed и его аналогов в плейбуках
  • Рефактория код системы управления конфигурациями:

    1. Разбейте задачи на логические сущности и перепишите монолит на роли
    2. Используйте линтеры! Ansible-lint, yaml-lint, etc
    3. Меняйте подход! Никакого bashsible. Нужно описывать состояние системы
  • Под все Ansible роли нужно написать тесты в molecule и раз в день генерировать отчёты.
  • В нашем случае, после подготовки тестов (которых больше 100) нашлось около 70000 ошибок. Исправляли несколько месяцев.


Наша реализация

Итак, ansible роли были готовы, шаблонизированы и проверены линтерами. И даже гиты везде подняты. Но вопрос надежной доставки кода в разные сегменты остался открытым. Решили синхронизировать скриптами. Выглядит так:



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

Вариантов создания серверов тоже много. Мы в итоге выбрали кастомные скрипты на питоне. А для CI ansible:

- name: create1.yml - Create a VM from a template  vmware_guest:    hostname: "{{datacenter}}".domain.ru    username: "{{ username_vc }}"    password: "{{ password_vc }}"    validate_certs: no    cluster: "{{cluster}}"    datacenter: "{{datacenter}}"    name: "{{ name }}"    state: poweredon    folder: "/{{folder}}"    template: "{{template}}"    customization:      hostname: "{{ name }}"      domain: domain.ru      dns_servers:        - "{{ ipa1_dns }}"        - "{{ ipa2_dns }}"    networks:      - name: "{{ network }}"        type: static        ip: "{{ip}}"        netmask: "{{netmask}}"        gateway: "{{gateway}}"        wake_on_lan: True        start_connected: True        allow_guest_control: True    wait_for_ip_address: yes    disk:      - size_gb: 1        type: thin        datastore: "{{datastore}}"      - size_gb: 20        type: thin        datastore: "{{datastore}}"

Вот к чему мы пришли, система продолжает жить и развиваться.

  • 17 ansible-ролей для настройки сервера. Каждая из ролей предназначена для решения отдельной логической задачи (логирование, аудит, авторизация пользователей, мониторинг и т.д.).
  • Тестирование ролей. Molecule + TestInfra.
  • Собственная разработка: CMDB + Оркестратор.
  • Время создания сервера ~30 минут, автоматизировано и практически не зависит от очереди задач.
  • Одинаковое состояние/именование инфраструктуры во всех сегментах плейбуки, репозитории, элементы виртуализации.
  • Ежедневная проверка состояния серверов с генерацией отчётов о расхождениях с эталоном.

Надеюсь мой рассказ будет полезен тем, кто в начале пути. А какой стек автоматизации используете вы?
Подробнее..

Как мы автоматизировали весь жизненный цикл серверов

15.07.2020 18:16:18 | Автор: admin

Привет, Хабр! Меня зовут Алексей Назаров. Я занимаюсь автоматизацией в отделе администрирования инфраструктурных систем в Национальной системе платежных карт (АО НСПК) и хотел рассказать немного о наших внутренних продуктах, которые помогают нам развиваться.
Если вы еще не читали пост про нашу инфраструктуру, то самое время! После прочтения этого поста я бы хотел рассказать о некоторых внутренних продуктах, которые мы разработали и внедрили.



В нашей компании, как и в любой другой, существуют свои регламенты и бизнес-процессы. Один из них это тот, по которому мы создаем сервера или стенд серверов по заявке Jira ServiceDesk. У сервера есть функциональный администратор, т.е. владелец. У серверов также имеется статус (Тестовый, Продуктивный, UAT и т.д.). Из-за статусов и других характеристик сервера должны находится в своем сегменте, датацентре, датасторе, сети и прочее. А значит, чтобы создать сервер сначала требуется: создать сервер в VMware, задать ему имя, ip, dns и другие немаловажные параметры, а потом уже прокатить ansible-playbook.


История развития


Я пришел в НСПК в январе 2015 года и работал в ситуационном центре дежурным линуксоидом. В наши основные обязанности входило создавать и настраивать сервера, поддерживать сервера в работоспособном состоянии. Когда система мониторинга показывала какие-то перебои c серверами, обращались к нам. 1-линии поддержки для эскалации требовалась информация о сервере: его назначение, за какую систему отвечает, кому он принадлежит и т.д. В случае срабатывания критичных триггеров в системе мониторинга 1-линия описывала подробную информацию о причинах и состоянии системы. Подробная информация о серверах на тот момент находилась у нас, так как серверами занимались мы. А значит мы также передавали подробную информацию о серверах 1-линии.


Для учета серверов мы использовали excel-файл. Для учета ip использовали phpIPAM https://phpipam.net/. phpIPAM open source продукт для учета адресным пространством. Еще некоторая информация могла находиться в самой системе мониторинга. Количество серверов насчитывалось не более 700.


В нашем отделе сотрудники отвечают за разные задачи: одни занимаются Виртуализацией и СХД, другие Windows, а мы Linux. Также есть отдел, где находятся сетевые инженеры и администраторы БД.


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


1) Требовалось узнать в каком датацентре, датасторе, сети и прочее
2) Создать сервер в требуемом сегменте через Vcenter
3) Прогнать bash-скрипты и некоторые ansible-playbookи
4) Добавить корректные данные о сервере в excel-файл
5) Добавить ip в phpIPAM
6) Закрыть заявку, если она была


Через некоторое время стало понятно, требуется создавать все больше и больше серверов. И мы стали искать варианты систем для хранения информации и учета серверов.
На просторах интернета таких систем немало. Даже в phpIPAM можно хранить информацию о серверах. Но в таких системах неудобно смотреть и анализировать состояние серверов в разрезе. В них не было необходимых полей и связей, нет фильтров по полям как в excel, нет четкого разграничения прав на редактирование и просмотр определенных серверов.
Мне тогда нравился Python, и я хотел сделать что-то на Django. Поэтому решил написать свою CMDB для нужд отдела и компании. После ее создания мы решили автоматизировать процесс создания и настройки серверов. Что получилось? Об этом далее


Мир серверов


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



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



Кроме хранения данных о серверах Мир серверов имеет функционал:


  • Разграничение прав доступа на просмотр и редактирование данных (по департаменту, по управлению, по отделу)
  • Удобный просмотр серверов в табличном виде, фильтр по любым полям, показ/скрытие полей
  • Разнообразные оповещения по почте
  • Актуализация информации о серверах
  • Ежедневный сбор данных о серверах и хранение для аналитики по ресурсам систем


  • Поиск и сравнение установленных приложений на серверах


Интеграция Мира серверов с другими системами:
1) Автоматическое обновление ip в phpIPAM
2) Выполнение заявок Jira ServiceDesk на предоставление нового сервера (стенда серверов) через Мир серверов
3) Просмотр расположения физического сервера и правильность заполнения информации в системе dcTrack (https://www.sunbirddcim.com/)
1) Передача информации о серверах через REST API для Zabbix и других систем мониторинга
2) Передача информации о ПО установленного на серверах через REST API для нужд ИБ
3) Синхронизация владельцев серверов из 1С и Active Directory для получения ФИО, рабочей почты, принадлежность к подразделению, статусе сотрудника. Надо написать, что такие данные требуется для разграничения прав, а также для автоматического оповещения владельцев серверов о ряде событий, связанных с их серверами.


DitNet


Наша инфраструктура на данный момент имеет более 10 ЦОД. Из этого понятно, что Мир серверов не сможет в любом сегменте создать и настроить сервер из-за понятных требований PCI-DSS.
Поэтому при выполнении заявок на предоставление сервера мы формируем json с данными, которые требуется для создания в среде VMware. Передача json реализована через защищенный rsync или ftps зависит от сегмента.
Надо заметить, что наш отдел провел очень большую работу. Убрали bashsible, переработали ansible на идемпотентные роли для настройки серверов, настроили molecule (https://molecule.readthedocs.io/), унифицировали все артефакты VMware и много чего другого. Стандартизация артефактов VMware потребовалась по большей части для серверных подсетей во всех ЦОДах (у нас их уже больше 900).
Как пример:
Раньше Distributed Switch мог называться test2, а теперь 192.168.1.0|24_test2. Данное переименование требовалось, чтобы можно было на этапе формирования json сделать матчинг подсетей из phpIPAM и VMware.


Выполнение заявок по предоставлению серверов:
1) DitNet ежедневно или по запросу собирает все артефакты из VMware (кластеры, датасторы, сети, шаблоны и т.д). Упаковывает всю информацию в json и отправляет в Мир серверов
2) Мир серверов принимает данные и наполняет данные БД артефактами VMware
3) В Мире серверов имеется страница, которая обращается к Jira ServiceDesk и по jql-запросу получает список заявок на предоставление серверов со статусом Очередь. На этой странице исполнитель заполняет таблицу артефактами VMware и другими ресурсами (Рис. Ниже). Часть данных автоматически заполняется данными, которые были указаны в заявке.



4) После заполнения и нажатия кнопки Сотворить, заявка меняет статус в Jira ServiceDesk В работе
5) В этот момент Мир серверов формирует json с данными о создании ВМ (артефакты, dns, ip и т.д.) и перекладывает его в папку для своего сегмента (определяется по домену сервера)
6) Каждый DitNet в своем сегменте запрашивает данные из своей папки и обогащает данными таблицу с серверами на установку. В БД имеются дополнительные поля с информацией по статусу установки (по умолчанию: готов к установке)
7) На DitNet каждые 5 минут отрабатывает Celery beat, который по статусу установки определяет количество серверов, которые требуется установить и настроить
8) Celery worker запускает несколько последовательных задач:
a. Создает сервер в VMware (используем библиотеку pyvmomi)
b. Скачиваем или обновляем проект gitlab по настройке сервера
c. Запускается Ansible-playbook (используем данный гайд https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html)
d. Запускается Molecule
e. Отправка почты исполнителю и Миру серверов о статусе выполнения
9) После каждой задачи проверяется статус. Если все задачи выполнены оповещаем исполнителя с сформированной ссылкой для закрытия заявки Jira ServiceDesk. Если какая-нибудь из задач провалилась, то оповещаем исполнителя с логом Vmware или Ansible.


Что еще умеет Ditnet на данный момент:


  • Собирает все данные и ресурсы со всех серверов. Для данной задачи мы используем Ansible с модулем setup. На хостах кроме локальных фактов используем также кастомные. Перед каждым запуском формируем инвентарь для Windows и Linux.
  • Собирает информацию SNMP о физических серверах. Сканируем определенные подсети и получаем серийный номер, версию BIOS, версия IPMI и т.д.
  • Собирает информацию о группах серверов в Freeipa (HBAC, SUDO правила), о группах в Active Directory. Для сбора и контроля ролевой модели доступа пользователей к информационным системам
  • Переустановка серверов
  • А еще там на заднем фоне котики. Рисунок ниже:


Вся информация, которую собирает DitNet, отправляется в Мир серверов. А там уже и проходит вся аналитика и актуализация данных о серверах.


Как мы обновляемся


В данный момент над Миром серверов и DitNet тружусь уже не только я. Нас уже три человека.
Весь исходный код хранится в наших Gitlab для удобной параллельной разработки. В каждом из проектов имеется свой Ansible-playbook, который запускает Gitlab CI и обновляет приложение. Pipeline:



По pipeline видно, что не хватает unit-тестов. Но, думаю, мы в скором будущем это исправим.
Также Ansible-playbook можно запустить через Ansible Tower (AWX) на новых серверах, если требуется новая инсталляция.
В случае с DitNet мы используем docker, чтобы доставлять нужные библиотеки во все сегменты. Он описан docker-compose. А docker-compose services завернуты в systemd.


Планируется в будущем


  • Автоматическое выполнение заявок на установку серверов без исполнителя
  • Плановое автоматическое обновление серверов
  • Добавление в Мир серверов сущности СХД и автоматический сбор данных
  • Сбор информации с физических серверов о всех комплектующих для отправки в Мир серверов для контроля ЗИПа серверов
  • Автоматическое оповещение об уходе из компании владельца сервера для последующей привязки серверов к будущему владельцу
  • Продолжение интеграции с другими системами компании
    и много еще интересного!

P.S. Спасибо за Ваше время! Критика и комментарии приветствуются!

Подробнее..

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

24.09.2020 12:15:14 | Автор: admin
Привет, Хабровчане! Мы Владимир Мясников и Владислав Егоров представители команды интеграционного тестирования Mir Plat.Form (АО НСПК). Сегодня мы расскажем про разработанный и развиваемый нами инструмент автоматизации, позволивший сократить рутину во внутренних процессах команды.

Предисловие


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



На данный момент команда работает с 13 системами уровня mission и business critical. Mission critical системы обеспечивают выполнение Mir Plat.Form своих основных функций, обеспечивающих стабильность и непрерывность функционирования банковской карточной системы РФ. Системы уровня business critical отвечают за поддержку предоставляемых клиентам Mir Plat.form дополнительных сервисов, от которых зависит непосредственная операционная деятельность компании. Частота выкатывания релизов в ПРОД варьируется от раза в неделю до раза в квартал, всё зависит от системы и готовности участников к частоте обновлений. В общей сложности мы насчитали около 200 релизов, прошедших через нашу команду в прошлом году.

Простая математика гласит следующее: количество проверяемых цепочек это N-систем * M-интеграций между ними * K-релизов. Даже на примере 13 систем * 11 интеграций * 27 версий релизов получается примерно 3 861 возможных вариантов совместимости систем. Кажется, ответ очевиден автотесты? Но проблема чуть серьезнее, только автотесты не спасут. Учитывая растущее количество систем и их интеграций, а также различную частотность релизов, всегда имеется риск протестировать неправильную цепочку версий систем. Следовательно, имеется риск пропустить дефект в межсистемном взаимодействии, например, влияющий на корректность работы платежной системы (ПС) Мир.

Естественно, в ПРОДЕ наличие такого рода багов недопустимо, и задача нашей команды свести такой риск до нуля. Если помните текст выше, любой чих влияет не только на внутренние системы Mir Plat.form, но и на участников рынка: банки, торгово-сервисные предприятия (ТСП), физические лица и даже на другие платежные системы. Поэтому для устранения рисков мы пошли следующим путем:

Ввели единую базу выпуска релизов. Для этой задачи вполне хватило календаря релизов в Confluence с указанием версий систем, установленных в ПРОД;

Отслеживаем интеграционные цепочки в соответствие с релизными датами. Здесь мы тоже не стали изобретать велосипед, он нам потребуется дальше. Для решение данной задачи использовали Epic структуры в JIRA для интеграционного тестирования релизов. Пример структуры для релиза 1.111.0 системы System3:



С одной стороны, все эти действия позволили улучшить понимание команды о тестируемых интеграциях, версиях систем и последовательности их выхода в ПРОД. С другой все равно осталась вероятность некорректного тестирования вследствие человеческого фактора:
  1. В случае, если дату релиза какой-нибудь системы подвинули, то члену команды необходимо вручную поправить календарь и всю структуру в JIRA, в том числе сроки выполнения задач и, возможно, версии тестируемых систем;
  2. Перед тестированием интеграции необходимо убедиться, что окружение для тестирования состоит из нужных версий систем. Для этого необходимо вручную пробежаться по тестовым стендам и выполнить пару консольных команд.

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

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

Какие опции хотелось реализовать в разрабатываемой системе?
1. Наглядный календарь релизов с возможностью вывода версий всех систем на конкретную дату;
2. Мониторинг окружений для интеграционного тестирования:
список окружений;
наглядное отображение тестовых стендов и систем, входящих в состав отдельного окружения;
контроль версий систем, развернутых на тестовых стендах.
3. Автоматизированную работу с задачами в Jira:
создание Epic структуры релиза;
управление жизненным циклом задач на тестирование;
актуализация задач в случае сдвига даты релиза;
подкладывание allure-отчетов в задачи на тестирование.
4. Автоматизированную работу с ветками в Bitbucket, а именно создание релизных веток в проектах:
интеграционных автотестов;
автодеплоя интеграционного окружения.
5. Интуитивно понятный UI для запуска автотестов и обновления версий систем.

Что есть СМИТ


Так как система несложная, мы не стали особо мудрить с технологиями. Бэкенд написали на Java с использованием Spring Boot. Фронтенд на React. К базе данных особенных требований не было, поэтому мы выбрали MySql. Поскольку у нас принято работать с контейнерами, то все вышеперечисленные составляющие завернули в Docker, собирая при помощи Docker Compose. Работает СМИТ быстро и так же надежно, как остальные системы Mir Plat.Form.



Интеграции


Atlassian Jira. В джире создаются, открываются, принимаются в работу и закрываются задачи на тестирование каждой конкретной интеграции, если все тесты прошли успешно прикладывается ссылка на allure отчет в комментарии.
Atlassian BitBucket. В битбакете лежит код проекта автотестов, где инженеры по автоматизации ведут список окружений, настраивают его и добавляют/убирают системы в определенные окружения. Также там создаются релизные ветки под каждую новую версию системы, где будут вестись работы по актуализации кода и бизнес логики тестовых сценариев.
Jenkins. Все тесты из проекта автотестирования можно запускать через Jenkins, для каждого набора тегов у нас предусмотрена своя джоба. Отдельные джобы нужны для того, чтобы не грузить все шаги каждый раз, а загружать только нужные с помощью указания glue для Cucumber.
Системы. У СМИТа есть необходимость взаимодействовать с самими системами. Так СМИТ узнает актуальные версии систем путем выполнения определенных команд по ssh.

Ведение списков систем


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



После добавления тестируемой системы в список СМИТ:
  1. постучится на все хосты систем, имеющих название SYS_CMD в списке окружений;
  2. узнает версию этой системы с помощью команды, указанной в конфигурации;
  3. запишет к себе в базу текущую версию данной системы и окружения, в которых она фигурирует.


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

Календарь релизов


После того, как владельцы систем или тим лиды команд разработки продуктов сообщают нам дату установки нового релиза в ПРОД, мы регистрируем этот релиз в календаре. Получается вот такая вот картина:



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

Также на странице с календарем имеется функция вывода версий всех систем на конкретную дату:



Стоит отметить, что при регистрации нового релиза в календаре СМИТ автоматически создает Epic структуру в Jira и релизные ветки в проектах в Bitbucket.

Состояние окружений


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



Как видно на скриншоте, СМИТ обнаружил на хосте host-4.nspk.ru неактуальную версию System 4 и предлагает обновить её. Если нажать красную кнопку с белой стрелкой, то СМИТ вызовет Jenkins джоб на деплой актуальной версии системы в текущем окружении. Также есть возможность обновить все системы после нажатия соответствующей кнопки.

Окружения для интеграционного тестирования


Стоит немного рассказать про то, как мы задаем тестовые окружения. Одно окружение представляет собой некий набор стендов с развернутыми системами Mir Plat.form и настроенной интеграцией (на одном стенде одна система). В общей сложности у нас 70 стендов, разбитых на 12 окружений.

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

{     "properties":{        "comment":"Общие system property для всех Environment. Могут быть переопределены персональными property, а также всем, что при запуске тестов в System.getProperties()",      "common.property":"some global property"   },   "environments":[        {           "comment":"Если отсутствует name, то Environment получит имя common + порядковый номер. Например common1",         "name":"env_1",         "properties":{              "comment":"Персональные system property данного Environment. Могут переопределять общие property. Могут быть переопределены всем, что при запуске тестов в System.getProperties()",            "env1.property":"some personal property"         },         "DB":{              "comment":"Пример TestResource'а DbTestResource. Если не указано поле id, то оно автоматически будет взято из ключа",            "url":"jdbc:mysql://11.111.111.111:3306/erouter?useUnicode=yes&characterEncoding=UTF-8&useSSL=false",            "driver":"com.mysql.jdbc.Driver",            "user":"fo",            "password":"somepass"         },         "SYS_CMD":{              "comment":"Пример TestResource'а на основе RemoteExecCmd. Должен иметь параметр type = remote",            "type":"remote",            "host":"10.111.111.111",            "username":"user",            "password":"somepass"         }      }   ]}


Помимо того, что данный файл необходим для работы проекта интеграционных автотестов, он также является дополнительным конфигурационным файлом для СМИТа. При запросе обновлении информации об окружениях в СМИТе отправляется HTTP запрос в API нашего bitbucket, где мы храним проект с интеграционными автотестами. Таким путем СМИТ получает актуальное содержимое файла конфигураций из master ветки.

Запуск тестов


Одной из целей создания СМИТа было максимальное упрощение процедуры запуска интеграционных автотестов. Рассмотрим, что же у нас получилось в итоге на примере:



На странице тестирования системы (в данном примере System 3) можно выбрать перечень систем, с которыми нужно проверить интеграцию. После выбора нужных интеграций и нажатия на кнопку Запустить тестирование, СМИТ:
1. Сформирует очередь и последовательно запустит соответствующие Jenkins джобы;
2. мониторит выполнение джоб;
3. меняет статус у соответствующих задач в Jira:
Если джоба отработала успешно задача в Jira будет автоматически закрыта, к ней будет приложена ссылка на allure-отчет и комментарий о том, что дефектов в данной интеграции не обнаружено.
Если джоба зафейлена задача в Jira останется открытой и будет ожидать решения от ответственного за интеграцию сотрудника, который сможет определить причину падения тестов. Ответственного за интеграцию можно подсмотреть в карточке интеграции.

Вывод


СМИТ был создан для минимизации рисков интеграционного тестирования, но нам как команде хотелось бОльшего! В частности, одним из желаний было, чтобы по одному нажатию кнопки автотесты запускались с правильным тестовым окружением, проверялось все в нужных интеграционных соответствиях, задачи в Jira сами открывались и закрывались вместе с отчетами. Такая утопия автотестеров: скажи системе, что проверить, и иди пить кофе :)

Подведем итог, что у нас получилось реализовать:
1. Наглядный календарь релизов с возможностью вывода версий всех систем на конкретную дату;
2. UI для отслеживания состояния наших окружений, позволяющий посмотреть перечень и версии систем, установленных на конкретном окружении;
3. Оповещение пользователей о неактуальных версиях систем с возможностью обновления до актуальной;
4. UI с интуитивно понятным запуском интеграционных автотестов для всей системы или для отдельных интеграций на определенном окружении;
5. Автоматическое создание и закрытие Epic и Task в Jira, прикладывание Allure отчетов к ним;
6. Автоматическое создание релизных веток в Bitbucket.

О планах на будущее


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

Архитектура экосистем

15.12.2020 10:11:51 | Автор: admin

Термин Экосистема появился в бизнес-лексиконе в 1993 году. Американский ученый Джеймс Мур в статье Хищники и жертва: новая экология конкуренции так обозначил модель объединения компаний вокруг решения единой стратегической задачи. Последнее время термин особенно популярен. Упоминаемость экосистемной бизнес-модели на пике в деловых новостях, бизнес-публикациях, финансовых отчетах и программах развития корпораций. Бизнес-экосистемам посвящаются деловые форумы и конференции.

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

Для начала все-таки придется посвятить пару слов лирике - природе и этапам становления экосистем. Это поможет выровняться в понимании самого термина.

В ретроспективе 25-30 лет экосистемная бизнес-модель эволюционировала. На этапе зарождения этого понятия под экосистемой понималось в большей степени объединение вокруг одного продукта конкурирующих между собой поставщиков и производителей. Пример - разработчики клиентского ПО для компьютеров Apple или производители аппаратных компонентов для ПК IBM. Превалировала классическая платформенная модель, которая решала задачу расширения и максимизации ассортиментного состава клиентских продуктов или составных компонентов одного продукта. Сегодня экосистемы приобрели сложный сетевой характер.Бизнес-экосистема выполняет роль источника ресурсов и знаний для развития компаний-участников. Синергетический эффект от участия в экосистеме стал проявляться в намного большем объеме. Продукты и сервисы этой бизнес-модели обогащают друг друга технологиями, функциями и операционными данными.Технологии - главный драйвер эволюции и становления экосистемной бизнес-модели. Тридцать лет назад в розничном бизнесе преобладал Product-centric подход. Главной задачей было грамотно сегментировать клиентскую аудиторию, правильно позиционировать товар, сформировать стратегию продвижения и дистрибуции. С ростом популярности персональных компьютеров, развитием телекоммуникаций, Интернет-технологий и появлением смартфонов возникла ориентация на каналы продаж - WEB-first, Mobile-first, Voice-first. Появилась электронная торговля и продвижение. Золотая полка, статичная и ограниченная в размерах в офлайн-ритейле по причине расположения на уровне глаз покупателя, в электронных каналах продаж стала безграничной и кастомизируемой под каждого клиента. Бизнес представил взору клиента весь товарный ассортимент. Взрывной рост и отрыв от конкурентов получили компании, которые быстро освоили новые каналы продаж и переориентировались на платформенную электронную бизнес-модель. Netflix и Zappos вырвались вперед в конкурентной борьбе, когда предложили клиентам больший ассортимент через онлайн-каналы. Крупнейшим розничным банкам взаимодействие через личные кабинеты клиентов помогло расширить набор финансовых продуктов.

Дальнейший рост вычислительных возможностей, доступности хранилищ данных и их логистики привели к появлению клиенто-центричного подхода в розничном бизнесе. Каждый клиент компании стал отдельным самостоятельным сегментом. Благодаря технологиям регистрации, обработки и анализа неструктурированных операционных данных, бизнес научился предугадывать клиентское поведение и предвосхищать ожидание клиента. Дополнительным катализатором послужило появление CEP (Complex Event Processing) и RTDM (Real-Time Decision Manager) -решений, которые обеспечили анализ информации на лету. Большие данные перестали анализировать по ночам. Интернет-компании за мгновения узнают пользователя и отображают таргетированную рекламу или цену товара уже после обращения к WEB-странице. Благодаря предиктивной аналитике физическое формирование посылки с товарами начинается одновременно с наполнением корзины на сайте - до момента оплаты товара клиентом. А предложение международной страховки направляется клиенту финансовой компании сразу после оплаты покупки в аэропорту.

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

Накопленные подходы и технологии позволили бизнесу создать новые способы конкуренции и, как следствие, новые бизнес-модели. Если раньше корпорации конкурировали с помощью технологий, то теперь - с помощью инновационных бизнес-моделей. Онлайн-магазины становятся Маркетплейсами, поставщики услуг и контента создают мультисервисные Онлайн-платформы, мобильные приложения трансформируются в Супераппы, а поставщики life-style сервисов объединяются вокруг клиента в единую электронную микросреду.

Эти профильные бизнес-модели и объединяет понятие Экосистема.

К текущему моменту сложилось две модели появления экосистем Европейская и Американо-Китайская. Первая модель предполагает децентрализованное объединение компаний - чаще стартапов - на основе единых правил, утверждаемых глобальным государственным или межгосударственным регулятором Центральным банком. Вторая модель предполагает объединение вокруг одного глобального финтех или бигтех игрока десятков меньших по объему бизнеса продуктов и сервисов. Примеры таких экосистем - Facebook, Amazon, Microsoft, Google, Apple (FAMGA) и Baidu, Alibaba, Tencent (BAT).

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

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

Для экосистем характерен ряд свойств, которые отличают их от стратегических альянсов, а также вертикально- и горизонтально-интегрированных компаний:

  • Наличие больших ресурсов для регулярных исследований, опытов и развития решений

  • Использование новых технологий, архитектуры и подходов к разработке ПО

  • Регулярная работа с большими данными

  • Цифровые бизнес-процессы

  • Отсутствие бюрократии в производственном процессе, сокращенный Time-to-market

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

Для клиента такая бесшовная мультисервисная среда включает, например:

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

  • Возможность не вводить многократно свои данные в профилях разных сервисов

  • Доступность нужных сервисов в разных интерфейсах (каналах, продуктах) экосистемы

  • Использование единого платежного инструмента, подписки, бонусной программы

  • Просмотр релевантного контента и предложений

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

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

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

  • Сервисы обеспечения омниканальности.

  • Единую учетную запись.

  • Единый ID клиента и клиентский профиль.

  • Доступность основных сервисов и функций через API.

  • Централизованный клиентский биллинг экосистемы.

  • Ориентацию на событийную модель интеграции (Event-Driven Architecture).

  • Единый контакт центр и службу поддержки.

  • Единый аналитический и операционный CRM.

Рассмотрим некоторые из них подробней.

Омниканальность

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

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

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

Единая учетная запись

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

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

Единый ID клиента и клиентский профиль

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

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

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

Единый платежный инструмент и централизованный клиентский биллинг экосистемы

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

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

Событийная интеграция систем (Event-Driven Architecture)

Используя перекрестное обогащение знаниями о клиенте компании создают сложные механики анализа клиентского поведения. Они помогают предвосхищать желания и потребности клиентов и предлагать релевантную продукцию товары, контент, услуги. На таком подходе построены концепции Next Best Offer (NBO) и Next Best Action (NBA). В рамках этих решений определяется, какой товар клиент с высокой вероятностью приобретет в конкретный момент (или период) времени. И, соответственно, какое действие клиент будет готов совершить в следующий момент. Для принятия таких решений компании анализируют в режиме real-time до тысячи триггеров клиентского поведения состав покупок, суммы, тип ТСП, запрашиваемый контент, проставленные в соцсетях лайки, среднее время просмотра роликов, контакты и многое другое. Но главное, решение на основе такого анализа необходимо принимать на лету, так как спустя время готовность клиента к приобретению товара или действию может сильно снизиться и предложение станет не актуальным. Поэтому для такого рода задач важна событийно-ориентированная интеграционная архитектура. Каждый домен экосистемы (как совокупность информационных систем) должен уведомлять другие домены о событиях в жизни клиента. Поэтому необходима организация супермаркета операционных данных - решения, которое позволяет информационной системе в онлайн-режиме получать важные для себя данные (например, на базе брокера сообщений Apache Kafka). Прямая интеграция систем для получения данных по запросу или рассылки сообщений о событиях создаст спагетти-архитектуру и, как следствие: существенный прирост нагрузки на системы, более сложное сопровождение, а также предпосылки для большего количества доработок в случае расширения атрибутного состава клиентских данных.


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

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

Поэтому включение нового клиента в экосистему происходит по заранее и детально спроектированному клиентскому пути (Customer Journey). А работа с одним сервисом упрощает клиенту работу с другими сервисами.

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

Подробнее..

Системный подход к переменным в Ansible

07.08.2020 12:20:56 | Автор: admin

ansible devops codestyle


Hey! Меня зовут Денис Калюжный я работаю инженером в отделе автоматизации
процессов разработки. Каждый день новые сборки приложений раскатываются на сотнях
серверов кампании. И в этой статье я делюсь опытом использования Ansible для
этих целей.


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


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

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



Переменные в ролях


Роль это отдельный Объект системы деплоя. Как и любой объект системы, он
должен иметь интерфейс взаимодействия с остальной системой. Таким интерфейсом
являются переменные роли.
Возьмём, для примера, роль api, которая устанавливает Java приложение на
сервер. Какие переменные у неё могут быть?



Переменные роли можно разделить на 2 вида по типу:


1. Свойства    a) независимые от среды    б) зависимые от среды2. Связи    a) слушатели     б) запросы внутри системы    в) запросы в среду

Переменные свойства это переменные, которые определяют поведение роли.


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


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


С другой стороны, 1а, 2а, 2б это переменные, которые не зависят от среды
(железо, внешние ресурсы и т.д.) и могут быть заполнены дефолтными значениями в
defaults роли. Однако переменные типа 1.б и 2.в заполнить кроме как 'example'
значениями невозможно, так как они будут меняться от стенда к стенду в
зависимости от окружения.


Code style


  • Название переменной обязательно должно начинаться с названия роли. Это позволит
    в дальнейшем легко разобраться, из какой роли переменная и за что она отвечает.


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


  • Старайтесь не использовать словари для переменных. Ansible не позволяет
    удобно переопределять отдельные значения в словаре.
    Пример плохой переменной:


    myrole_user:    login: admin    password: admin
    

    Здесь login средонезависимая переменная, а password зависимая. Но
    поскольку они объединены в словарь, вам придётся задавать её полностью
    всегда. Что очень неудобно. Лучше так:


    myrole_user_login: adminmyrole_user_password: admin
    


Переменные в плейбуках деплоя


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


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


mydeploy                        # Каталог деплоя deploy.yml                  # Плейбук деплоя group_vars                  # Каталог переменных плейбука  all.yml                 # Файл для переменных связи всей системы  myapi.yml               # Файл переменных свойств группы myapi inventories                 #     prod                    # Каталог окружения prod       prod.ini            # Инвентори файл       group_vars          # Каталог для переменных инвентори         myapi           #           vars.yml    # Средозависимые переменные группы myapi           vault.yml   # Секреты (всегда средозависимы) *

* Variables and Vaults


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


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


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


Переменные свойств для групп


Расширим нашу модель на рисунке 1, добавив 2 группы серверов с другим Java
приложением, но с разными настройками.



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


- hosts: myapi  roles:    - api- hosts: bbauth  roles:    - auth- hosts: ghauth  roles:    - auth

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


Code Style


  • Старайтесь вообще не использовать host_vars переменные, поскольку они не
    описывают систему, а только частный случай, что в перспективе приведёт к
    вопросам: "А почему этот хост отличается от остальных?", ответ на который не
    всегда легко найти.

Переменные связи


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


По началу была идея использовать монструозную конструкцию вида:
hostvars[groups['bbauth'][0]]['auth_bind_port'], но от неё сразу отказались
поскольку она имеет недостатки. Во-первых, громоздкость. Во-вторых, зависимость
от определенного хоста в группе. В-третьих, необходимо перед началом деплоя
собрать факты со всех хостов, если мы не хотим получить ошибку неопределённой
переменной.


В итоге решено было использовать переменные связи.


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


Переменные связи заполняются в общих переменных системы group_vars/all/vars и
образуются путём выноса всех переменных слушателей из каждой группы, и
добавлением в начало переменной название группы откуда слушатель был вынесен.
Таким образом обеспечивается однотипность и непересекаемость имён.


Попробуем связать переменные из примера выше:



Представим, что у нас есть переменные, которые друг от друга зависят:


# roles/api/defaults:# Переменная запросаapi_auth1_address: "http://example.com:80"api_auth2_address: "http://example2.com:80"# roles/auth/defaults:# Переменная слушательauth_bind_port: "20000"

Вынесем в общие переменные group_vars/all/vars всех слушателей, и добавим в
название имя группы:


# group_vars/all/varsbbauth_auth_bind_port: "20000"ghauth_auth_bind_port: "30000"# group_vars/bbauth/varsauth_bind_port: "{{ bbauth_auth_bind_port }}"# group_vars/ghauth/varsauth_bind_port: "{{ ghauth_auth_bind_port }}"# group_vars/myapi/varsapi_auth1_address: "http://{{ bbauth_auth_service_name }}:{{ bbauth_auth_bind_port }}"api_auth2_address: "http://{{ ghauth_auth_service_name }}:{{ ghauth_auth_bind_port }}"

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


Code Style


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

Средозависимые файлы


В ролях могут использоваться файлы, которые отличаются от среды к среде.
Примером таких файлов можно назвать SSL-сертификаты. Хранить их в текстовом виде
в переменной не очень удобно. Зато удобно хранить путь до них внутри переменной.
Например, используем переменную api_ssl_key_file: "/path/to/file".


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


Удобнее всего в этом случае положить файл ключа в репозиторий плейбука по пути
files/prod/certs/myapi.key, тогда значение переменной будет:
api_ssl_key_file: "prod/certs/myapi.key". Удобство же заключается в том, что
люди отвечающие за разворачивание системы на конкретном стенде, так же имеют
своё выделенное место в репозитории для хранения своих файлов. В то же время
остаётся возможность указать абсолютный путь до сертификата на сервере, на
случай если сертификаты поставляются другой системой.





Несколько стендов в одной среде


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





Окончательная структура каталогов для проекта деплоя:


mydeploy                        # Каталог деплоя deploy.yml                  # Плейбук деплоя files                       # Каталог для файлов деплоя  prod                    # Католог для средозависимых файлов стенда prod   certs               #        myapi.key       #  test1                   # Каталог для средозависимых файлов стенда test1 group_vars                  # Каталог переменных плейбука  all.yml                 # Файл для переменных связи всей системы  myapi.yml               # Файл переменных свойств группы myapi  bbauth.yml              #   ghauth.yml              # inventories                 #     prod                    # Каталог окружения prod      group_vars          # Каталог для переменных инвентори       myapi           #        vars.yml    # Средозависимые переменные группы myapi        vault.yml   # Секреты (всегда средозависимы)       bbauth          #         vars.yml    #        vault.yml   #       ghauth          #           vars.yml    #           vault.yml   #      prod.ini            # Инвентори стенда prod     test                    # Каталог окружения test         group_vars          #          myapi           #           vars.yml    #           vault.yml   #          bbauth          #           vars.yml    #           vault.yml   #          ghauth          #              vars.yml    #              vault.yml   #         test1.ini           # Инвентори стенда test1 в среде test         test2.ini           # Инвентори стенда test2 в среде test

Подведение итога


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


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


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


Литература


  1. Документация

Автор


Калюжный Денис Александрович

Подробнее..

Как работают мобильные кошельки на примере приложения Mir Pay

31.08.2020 18:16:08 | Автор: admin
Как известно, в 2015 году мы запустили в эксплуатацию платежную систему Мир, и карты Мир в России принимаются повсеместно. Это, конечно, очень здорово, но сейчас набирает популярность использование мобильных кошельков для оплаты покупок. Согласно статистике, в 2019 году 19% всех операций составляют платежи при помощи смартфона. В 2017 году их было всего 3%. В 2018 году собственное платёжное приложение Mir Pay представила и платежная система Мир. Mir Pay написан на Kotlin, может работать на телефонах с поддержкой NFC и операционной системой Android 6.0 и выше.



Меня зовут Богданов Валерий, я являюсь руководителем группы тестирования в команде мобильных платежей департамента информационных технологий НСПК, и я расскажу о том, как работают мобильные кошельки на примере нашего приложения Mir Pay.

Сначала рассмотрим, как работает оплата с использованием пластиковой карты. В классическом случае карта выдается держателю банком-эмитентом. При этом карта в защищенной области памяти хранит общий с эмитентом ключ MK-AC (Application Cryptogram Master Key). Во время совершения оплаты (при online-операции) карта генерирует на основе MK-AC сессионный ключ SK-AC (Application Cryptogram Session Key) и на нем, с использованием данных карты и данных об операции, полученных с терминала, генерирует криптограмму ARQC (Authorization Request Cryptogram). В основе генерации криптограммы лежит алгоритм 3DES (Triple DES). В общем случае данные по операции поступают от карты к терминалу, далее на хост банка-эквайрера (т.е. обслуживающего торговую точку), затем к платежной системе и на самом последнем этапе к банку-эмитенту (т.е. выдавшему карту) для авторизации.



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

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



Держатель карты вводит данные в приложение (1), которое передает их в зашифрованном виде (об этом чуть позже) через хосты поставщика услуг мобильного кошелька (WSP Wallet Service Provider) в платежную систему. В случае с Mir Pay поставщиком услуг кошелька является НСПК, поэтому данные сразу попадают в платежную систему (2). Далее обработка происходит на платформе мобильных платежей (ПМП). ПМП расшифровывает данные, по номеру карты определяет, каким эмитентом она была выдана, и запрашивает у него подтверждение на возможность добавления карты в кошелек (3). В случае положительного ответа (4) для данной карты происходит процедура генерации токен-профайла (5) и отправка его на телефон (6). Таким образом, вместо карточных данных на мобильном устройстве будет храниться токен-профайл, привязанный к данной карте и данному устройству. Отметим, что преобразование токен-профайла в исходные карточные данные вне платформы мобильных платежей невозможно. После сохранения токен-профайла на устройстве пользователя Mir Pay запрашивает у ПМП (7) пачку одноразовых ключей, которые будут использоваться приложением при совершении покупки в качестве сессионных ключей, аналогичных упомянутым выше SK-AC. Как видно из названия, одноразовый ключ не может быть применен более одного раза, поэтому в процессе использования приложение Mir Pay периодически подгружает из ПМП новые порции ключей. На этом добавление карты в приложение завершается.

Теперь рассмотрим, как изменился процесс оплаты по сравнению с оплатой по пластиковой карте.



Первый этап почти такой же, только вместо данных карты используются данные токен-профайла, а криптограмма ARQC генерируется на одноразовом ключе, полученном от ПМП в качестве сессионного SK-AC. Еще одно отличие Mir Pay от пластиковых карт состоит в том, что при генерации криптограммы вместо 3DES используется более современный симметричный алгоритм блочного шифрования AES (Advanced Encryption Standard).

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

В Mir Pay используется схема с одноразовыми ключами, но существует и другой подход хранение одного ключа на устройстве. Такой подход требует наличия элемента безопасности на устройстве и некоторые кошельки могут его применять с учетом того, что на определенных устройствах такой элемент безопасности присутствует. В нашем случае, учитывая огромное многообразие телефонов с ОС Android это просто не достижимо. Данная специфика и объясняет выбранную схему.

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

Для обмена конфиденциальными данными ПМП и Mir Pay генерируют ключевые пары и обмениваются публичными компонентами. В силу того, что мы не можем на 100% доверять встроенному хранилищу ключей, была разработана схема с хранением разных ключевых компонент в разных местах: как в ключевом хранилище, так и в оперативной памяти. То есть для инициирования мошеннической операции необходимо, во-первых, извлечь криптограммы всех этих ключей, а во-вторых их нужно еще и расшифровать! Но это не так-то просто и не особо эффективно, поскольку для проведения операций используются строго одноразовые ключи. И только после того, как Mir Pay и ПМП обменялись публичными ключами, то есть фактически создали защищенный канал, допускается передача чувствительных данных, которые шифруются крипто-стойкими алгоритмами. По этому механизму на устройство пользователя доставляются и токен-профайл, и одноразовые ключи для проведения операций, и данные по уже совершенным операциям.

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

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

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

Как мы поощряем и развиваем ключевых сотрудников

04.02.2021 10:09:11 | Автор: admin

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

А с чего все началось?

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

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

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


High Potential (HiPo) высокопотенциальные сотрудники. Они проактивны в собственном развитии, инициативны, с лидерскими задатками;

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

Key Expert сотрудники, обладающие уникальными знаниями не только в рамках компании, но на рынке труда в целом.


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

После этого мы провели интервью с руководителями, спросив их о конкретных качествах High Potential, Best Performers и Key Experts. Что эти люди должны делать, чтобы руководитель увидел в одном большой потенциал, а в другом большую эффективность? Как описать их поведение?

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

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

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

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

Один человек мог попасть в несколько категорий сразу.

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

С каждой категорией ключевых сотрудников мы активно взаимодействуем в течение года.

High Potential:
Для каждого участника, прошедшего отбор:

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

Планируем индивидуальное обучение. Для каждого HiPo мы выделяем свой персональный бюджет на обучение (помимо того, что планируем на профессиональное обучение в рамках общей программы компании);

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

Best Performer:

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

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

Key Expert:

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

Награждаем наставников по результатам передачи знаний;

Пишем про коллег в корпоративных СМИ. Рассказываем о том, что они делают в компании, в чем уникальность их опыта и экспертизы.

Прошедшие 2 года программы принесли много позитивных отзывов. Мы не стоим на месте и постоянно совершенствуем проект. Очень радует, что каждый год количество желающих выдвинуть свою кандидатуру в HiPo прирастает. Наша самая первая группа HiPo сейчас уже работает над полезным для компании проектом, на подходе следующая группа, которая будет реализовывать своей проект. Также мы видим, что результаты обучения и развития сотрудников положительно влияют на их продвижение в компании (30% HiPo получили продвижение за последние 2 года).

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

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

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

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

Подробнее..

Категории

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

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru