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

Amazon web services

Монтируем видео на облачном сервере в AWS

01.05.2021 20:09:31 | Автор: admin

Мой рабочий компьютер - Macbook Air 2020 (Intel), и его вполне хватает для написания кода и прочих задач. Однако, когда потребовалось смонтировать небольшой видеоролик, выяснилось что мощи моего ноута катастрофически не хватает, и я стал искать варианты.

Что я пытался сделать

Я не занимаюсь профессиональным монтажом видео, и впервые уткнулся в эту тему пытаясь сделать вот такой небольшой демонстрационный ролик для Teamplify (с озвучкой помог Мэтт, наш учитель английского):

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

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

  2. Записать это единым куском практически невозможно - то замешкаешься где-то, то ошибешься, то интернет подтупит;

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

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

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

Монтаж видео требует ресурсов

Мои попытки работать с видео на Macbook Air были похожи на мучение. Оказалось, что After Effects любит побольше памяти, и моих 16ГБ явно не хватало. Ноутбучный проц и слабая видюха также не улучшали картину. Превью в After Effects работало с сильными лагами. Финальный рендер трехминутного ролика занимал 3 часа (!!).

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

Что нам может предложить AWS?

Мне он предложил примерно следующее:

  • Регион eu-north-1 (Стокгольм), пинг до меня ~30мс (я живу в Вильнюсе), до Москвы чуть побольше, но тоже неплохо - около 40мс;

  • Сервер g4dn.2xlarge - 8 ядер, 32ГБ, Nvidia Tesla T4, 225 GB NVMe SSD;

  • Образ винды с дровами от Nvidia;

  • Цену в $1.166 в час. И это кстати еще одна причина выбрать Стокгольм, ибо во Франкфурте на ~12% дороже.

Разумеется, можно взять и побольше, и поменьше. На момент написания статьи цены в Стокгольме такие (инстансы с Nvidia Tesla T4, на винде):

Подготовка к работе

Для коннекта к серверу я использовал Microsoft Remote Desktop. Сначала я думал, что мне потребуются какие-то специальные клиенты, рассчитанные на стриминг видео, но оказалось что и обычный Remote Desktop неплохо справляется, никаких особенных лагов я не замечал.

Остается решить вопрос с диском и доставкой исходников на него. Тут амазона предлагает нам два варианта - EBS и Instance Store. Отличаются они следующим:

  • EBS - подключаемый сетевой диск, по надежности примерно как RAID 1. Такой диск в вашем сервере обязательно будет как основной, по умолчанию он небольшого размера (достаточного чтобы влезла операционка), но вы можете при желании его расширить. Данные на EBS сохраняются и после выключения сервера. Платите вы за такой диск постоянно, даже если сервер выключен, в размере $0.0836 за ГБ в месяц (в версии gp3, burstable IOPS). У EBS есть разные варианты по производительности. Можно купить гарантированную производительность, но тогда она может влететь в копеечку, или же можно остаться на стандартном gp3, который основан на модели burstable IOPS. Когда диск простаивает, у вас накапливаются кредиты на IO, а когда он активно используется - они расходуются. Подробнее можно почитать в доках.

  • Instance store - так называемый эфемерный диск, который может идти в комплекте к некоторым типам инстансов. В частности, к g4dn.2xlarge прилагается 225 GB NVMe SSD. Он быстрый, производительность ничем не ограничена, однако данные на нем полностью пропадают при выключении сервера (при перезагрузке - остаются).

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

Когда диск готов, нужно как-то доставить на него исходники. Я использую для этого pCloud (аналог Dropbox), который установлен и на моем ноуте, и на облачном сервере. При старте сервера на нем запускается небольшой батничек, который инициализирует расшаренную папку pCloud (для исходников и результатов) и заодно создает папку для кеша After Effects:

mkdir Z:\"Teamplify Videos"mkdir Z:\"AE Cache"

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

Как возможную альтернативу Dropbox / pCloud можно еще рассмотреть что-то вроде ownCloud с хранилищем на S3. Если исходники будут выкачиваться из S3 в том же AWS регионе, что и ваш сервер, то это должно быть очень быстро, что может иметь значение при большом размере исходников.

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

И как это все работает?

Да вроде неплохо. Превью в After Effects нормальное, без лагов. Поскольку пинг до сервера хороший, работа на нем почти не отличается от работы с настольным компьютером. Рендер того ролика, который у меня на ноуте выполнялся три часа, на g4dn.2xlarge делается за 13-17 минут. День работы на таком сервере обходится в несколько долларов.

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

Подробнее..

Вебинар Создание эффективной инфраструктуры при помощи облачных решений

12.01.2021 04:18:24 | Автор: admin


19 января в 19:00 приглашаем на бесплатный вебинар Создание эффективной инфраструктуры при помощи облачных решений. На вебинаре расскажем об отличиях облачной инфраструктуры от традиционного подхода. Обсудим вопросы:


Как работают облака и какие проблемы они решают?
В чем разница между IaaS, PaaS и SaaS?
Как Netflix обслуживает десятки миллионов подписчиков по всему миру?
Global Presence: ваш ЦОД в любом уголке планеты.
Flexibiltity: от ста серверов до тысячи и обратно за несколько минут, адаптивно к нагрузке.
Модели оплаты Upfront/Pay as you go.


Спикер


Александр Волочнев, Developer Advocate в DataStax Inc.


Certified Professional Cloud Architect
Автор международных курсов для IT-специалистов
Более 8 лет опыта разработки и внедрения облачных решений
Спикер на многочисленных международных конференциях


Записаться на вебинар

Подробнее..

Авторизованные курсы AWS за или против

25.02.2021 10:21:06 | Автор: admin
Архитекторы и проектировщики решений, а также все, кто желает ими стать! Нам (Сетевой Академии ЛАНИТ) нужна ваша помощь. Мы в поиске новых направлений для развития, и один из вариантов авторизованные курсы по облачным технологиям Amazon. Расскажите, будет ли вам интересно такое обучение.


Architecting on AWS это курс об основах создания ИТинфраструктуры на платформе AWS. В ходе обучения вы научитесь оптимизировать облако AWS, проектировать оптимальные ИТ-решения на AWS и создавать различные инфраструктуры. Будем рады пожеланиям и предложениям в комментариях. Давайте обсудим.
Подробнее..

Почему в AWS все так сложно с прайсом и правами? Как избежать политических блокировок и защитить данные в облаке?

10.03.2021 14:15:34 | Автор: admin


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


Спикер вебинара Александр Волочнев (Developer Advocate в DataStax Inc.) и Всеволод Севастьянов (TechLead в vene.io) ответили на вопросы о прайсе и правах в AWS, рассказали, как защитить данные и в каких ситуациях лучше выбрать российских облачных провайдеров.


Зачем Openstack от %anyvendor% если есть открытая ванильная версия, разрабатываемая огромным количеством талантливых разработчиков?


Всеволод Севастьянов: Вопрос классный, если уточнить, что такое Openstack, так как есть 15 компаний, которые контрибьютят своих разработчиков на разработку непосредственно самого Openstack (HP, IBM и др.). И то, что они себе устанавливают, это по сути есть Openstack для их клауда с какими-то обертками, свистелками от непосредственно самих вендоров. Что выбирать для себя? Вопрос. Если вы берете Openstack, чтобы поставить на свои сервера, берите Openstack, если вам ничего сверху не надо. Если вы будете работать с HP-шными железками или с вещами, которые они вам предоставляют для облачных вычислений, для нейросетей или для коннекшена к облаку самого HP, берите HP-шный Openstack.


Александр Волочнев: Тут я должен сделать шаг в сторону и сказать, что не все знают, что такое Openstack, у нас вебинар для начинающих разработчиков. Openstack это возможность самому сделать свое собственное облако, то есть это такая система управления всяким железом и всем остальным, где с одной стороны сидите вы сами и запихиваете новые сервера, а с другой стороны люди пользуются этим как облаком. Обычно это для больших компаний актуально, где есть отдел, который делает все то же самое, что делает AWS, и есть отдел, который это все обеспечивает. То есть это такое домашнее облако, и есть несколько его поставщиков. Хороший вопрос, на который сложно однозначно ответить. Это как есть Linux Kernel, есть Ubuntu. Несколько холиварная тема, которую я пока что закрываю.


Почему в AWS все так сложно с прайсом? Сложно понять, сколько в итоге будет стоить проект?


Александр: Сложно, потому что AWS это система, которую инженеры создавали для инженеров. А когда инженеры берутся разрабатывать какую-то систему, они думают о том, чтобы все было технически правильно, а не просто. Большой проект иногда бывает проще разработать и внедрить, чем просчитать. Потому что AWS пошло по пути сверхточного вычисления, плюс у каждого сервиса есть отдельные классы, например, у сервиса хранения Simple Storage есть несколько классов хранения файлов. На одном классе хранения файлов у вас файлы будут храниться чуть подороже, но с вас не будут браться деньги, когда их кто-то скачивает, на других классах файлы будут храниться подешевле, но с вас будут браться деньги, когда их кто-то скачивает, причем первые 100 Гб с вас будут брать одну сумму, последующие 100 Гб с вас будут брать другую сумму. При этом, чтобы окончательно всех запутать, есть еще Intelligent Tiering, когда у вас файлы будут прыгать между слоями в зависимости тот того, как будет вам выгоднее, по мнению AWS.


И это я только про хранение файлов говорю в одной конкретной корзине. Если мы говорим про AWS Lambda, бессерверные приложения, там тоже красиво, потому что отдельно считается время, отдельно считаются запуски и отдельно считается потребление памяти в Гб/мс. На самом деле они хотели как лучше. Они хотели предоставить вам оплату потребления только того, что вы действительно потребили. Но поскольку они отдельно считают коннекшены, отдельно потребление, отдельно то-се, пятое-десятое Когда считаете какой-то проект, во-первых, посчитайте, что тарифицируется. Надо учитывать нюансы. Если вы, например, храните маленький файл в их AWS S3 Glacier, ледник служба длительного хранения файлов на магнитных лентах, самое дешевое хранилище, но не самое быстрое, надо учитывать, что там минимальный размер файла считается 100 с чем-то Кб, то есть надо учитывать, что если вы туда положили файл в 1 Кб, платить вы будете как за 100 Кб. Много нюансов, обсчет сложный. Это характерно для продуктов, разработанных инженерами для инженеров.


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


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


Как избежать чека в $1000, когда ожидаешь максимум $100-200, и при этом не остаться с заблокированным сервисом в час-пик?


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


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


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


Почему так сложно управлять правами доступа в AWS (IAM)? (Прописывание policy вручную, boundary и т.д.)


Александр: Я сначала отвечу на вопрос почему, а потом на вопрос как. Представьте себе на одной стороне отрезка самокат, а на другой самолет, Boieng 777 или что-то подобное. Самокат прост и интуитивно понятен. Вы можете с первого раза встать на него, поехать и через несколько минут с ним справиться, а пару раз набив шишки уже делать какие-то трюки. Порог вхождения низкий, возможности низкие. Вы не можете на самокат посадить себя, своего пьяного друга и два ведра грибов из леса. Мощность низкая, простое управление.


Мы начинаем говорить про мощные системы. Identity and Access Management для тех, кто может быть не знает, это система управления правами доступа в AWS, очень мощная. Она позволяет вам генерировать такие правила, что пользователю Васе разрешено будет использование такого-то сервиса с редактированием при, не знаю, восходящей фазе луны в три часа ночи после крика петуха, но не будет доступно все остальное время, и т.д. Любая мощная система не может быть простой. Это закон природы. Из хороших новостей. Да, порог вхождения высокий, но когда привыкаешь, все становится хорошо. И все эти штуки нужные, хорошие и правильные.


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


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


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


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


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


Александр: Биллинг любой системы сложнее велосипеда будет отставать, потому что это чертовски сложно. Есть возможность сделать биллинг быстрым. Но ценой потребления ресурсов с вашего сервера. То есть биллинг у вас будет риал-тайм, а сервер будет работать медленнее. Вы точно этого хотите? Всегда есть риск, что выйдет чек в тысячи долларов. Есть. Так вы границы задавайте. Все. Ставьте ограничение, кеширование, тротлинг на API Gateway.


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


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


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


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


Александр: Да, избегайте вендор-лока. То есть жесткой привязки к какому-то конкретному поставщику.


Насколько оправдано стремление к гибридному облаку?


Александр: Очень зависит от вашего проекта. Гибридное облако это когда часть проекта у вас запущена в AWS, а часть проекта запущена в вашем собственном датацентре. И они взаимодействуют друг с другом. Насколько это оправдано? Для небольших и средних проектов, я бы сказал, это не оправдано чаще всего. Для больших проектов это может быть оправдано, так как это может быть оптимальным способом уменьшения расходов. Все зависит от вашего юзкейса. Если вы хотите создать максимальную доступность и пережить падение облака, такое тоже возможно. Но это очень сложно, и для этого нужны очень хорошие спецы. То есть снова для большинства проектов это будет неактуальным. Проще, конечно, одно чистое облако. Любые интеграции буду всегда сложнее.


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


Александр: CAPEX (capital expences, капитальные расходы) подразумевается, что когда компания покупает новые сервера, она тратит много денег, ставит сервера себе как основные средства. И есть OPEX (operational expences), которые относятся к аренде, и если вы целиком в облаке, у вас все расходы на инфраструктуру являются операционными, и они списываются по-другому. Для некоторых компаний это может быть очень важно с точки зрения бухгалтерии и налогообложения.


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


Александр: Как говорят AWS и, полагаю, Azure тоже: Security is a shared responsibility. Безопасность это разделенная ответственность. Имеется ввиду, что часть безопасности организовывает облако, но как бы они ни старались, если вы со своей стороны о безопасности не позаботились, они вам ничем помочь не смогут. То есть это общая ответственность. Хотите безопасность, изучайте, как организовать безопасность.


И второй момент надо понимать, что с GCP, с Amazon работают очень серьезные американские правительственные компании, у которых сверх строгие требования по шифрованию и хранению данных. И облака регулярно проходят всевозможные виды аудитов, чтобы подтвердить, что у них есть все необходимое: все виды изоляции, все защиты, шифрования и сертификаты все вообще, что может только потребоваться. И для совсем Advanced-кейсов можно использовать Outpost, то есть можно разворачивать инфраструктуру AWS на базе вашего собственного железа.


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


Я рекомендую организовывать бастионы, то есть некоторые сервера-прокси, точки входа, изолировать базу данных внутри кластеров, настраивать сервисы Kubernetes так, чтобы они не отвечали ни на что, кроме white-listed IP или white-listed services, ну, и так далее, потому что это большой топик.


Что вы думаете насчет отечественных cloud-провайдеров, Yandex, Selectel? Просто ваше мнение и опыт использования, если есть.


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


Всеволод: Последний раз, когда я изучал этот рынок, помимо Яндекса и MCS все остальные провайдеры использовали в некотором смысле openstack-решения. И у них были очень классные решения поверх openstack и очень классный менеджмент. В целом если вы держите бизнес в России, наверное, имеет смысл. У Амазона, например, нет региона Россия.


Александр: Да, у GCP, по-моему, тоже. Если вы держите данные ваших пользователей в России, то Yandex и Selectel могут быть для вас хорошим выбором.


После вашего курса смогу ли я запустить свой проект (небольшой) в AWS c пониманием дела? Смогу использовать нужные абстракции и т. д.?


Александр: Да, безусловно, он для этого и разработан. Я прицеплю сюда еще вопрос ниже: У меня уже есть AWS-SAA01, стоит ли покупать курс Слёрм. Насколько он будет мне полезен? Один из ценных моментов курса возможность задать вопрос и быть услышанным. У Амазона с этим сложно, как правило, такой возможности нет. Я готов взаимодействовать и отвечать на вопросы.


Если вы хотите использовать какие-то сложные вещи, про них мы, может быть, в курсе и не говорим. Например, Амазон предоставляет роскошнейшие возможности для machine learning, у них там все автоматизировано, интегрировано, вообще супер. И это в облаке вообще огонь. Но про это мы не рассказываем в базовом курсе, потому что где базовый курс, а где machine learning? Если вы планируете использовать Fargate, про него мы не рассказываем в базовом курсе, но все стандартные вещи: EC2, S3, AutoScaling, базы данных, Serverly, Lambda, API Gateway, инфраструктура как код, которая помогает вам управлять вашим проектом, и т. д. это все есть.


Почему в России большинство компаний все еще косо смотрит на облака (в пользу in-house инфраструктуры) при всех их преимуществах? Когда ожидать сдвига в мышлении?


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


Александр: Нужно время на сдвиг парадигмы, наверное.


Сколько требуется времени для получения опыта или равноценного сертификата, который требуют работодатели для Cloud DevOps Engineer?


Александр: Во-первых, я не знаю, каких сертификатов требуют работодатели для Cloud DevOps Engineer. Если говорить про стандартные младшие позиции, если вы не претендуете на Senior Cloud DevOps, то у меня лично подготовка и сертифицирование для GCP заняла ровно месяц. Мне надо было перенести опыт архитектуры и разработки с AWS на GCP. Но это было много работы, я серьезно по много часов в день вкладывался. Что касается младших должностей, мне кажется, в качестве сайд-проекта базовую сертификацию в направлении Сloud DevOps нужно делать тоже за месяц. Если заниматься этим по паре-тройке часов в день, то это возможно. Это дело интересное и очень неплохо оплачивается в очень многих компаниях.


IAAS не всегда решает вопрос рабочих мест. Есть ли альтернативные способы реализации виртуальных рабочих мест кроме RDS (не гибко) и VDS (дорого)?


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


Amazon Outpost. Зачем и как применять?


Александр: Это классная возможность, когда вы можете поднять свой собственный ЦОД, и вы можете запустить весь софт AWS на вашей стороне, и вы будете использовать его как полностью интегрированный в инфраструктуру Амазон, но при этом это будет ваше железо, которое стоит у вас и которое охраняется вами, обеспечивается электричеством вами и т. д. Вот что такое Amazon Outpost. Зачем и как применять? Как применять не расскажу, потому что до сих пор не приходилось, это очень специфичный кейс. У меня нет опыта с Outpost никакого, просто никогда не было необходимости. Зачем? В некоторых ситуациях есть супер-строгие требования по аудиту, системам безопасности и т. д. то есть только у вас должны храниться данные и никуда они не должны попадать, с точки зрения аудита.


Какова разница между курсами Слёрма и AWS training?


Александр: Со своей стороны скажу вот что: AWS я больше изучал на практике и отдельно знакомился с некоторыми курсами, которые у них есть. С точки зрения организации обучения, мне очень понравился Google Cloud Platform. Он вперед на милю от AWS с точки зрения организации процесса, материалов для подготовки и т. д. Первая разница между курсами Слёрм и AWS: AWS на английском. Если у вас плохой английский, Слёрм здесь однозначно будет лучшим выбором. У AWS есть тренинги практически на любую тему. Не всегда полные, не всегда хорошие, но они есть. У Слёрм на данный момент есть только один курс по AWS. Это базовый курс, который закрывает все основные юзкейсы и самые наиболее часто используемые сервисы. Но если вам нужен какой-нибудь хитровывернутый кейс, то этого может не оказаться в нашем курсе, опять-таки, курс называется базовый. И последнее Слёрм обеспечивает определенную поддержку: можно написать, можно сказать, что в практике написано вот так, у меня так не получается, что пошло не так? В AWS Training писать будет некому.


На сколько порядков отличается цена за единицу ресурсов облака для Netflix и стартапа?


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


Где границы между разумным использованием Iaas, PaaS, SaaS?


Александр: Все зависит от того, как много у вас специалистов в этой отрасли, насколько у вас хватает мощностей. Первое правило аутсторса: аутсорсить то, что для вас не принципиально, то, на чем вы не зарабатываете деньги, что не является ключом вашей бизнес-модели. Если вы делаете что-то, что не является для вас принципиальным, это склоняет вас ближе к SaaS. Saas и PaaS очень близки. Вы разрабатываете бессерверное приложение: у вас база данных будет SaaSом, а приложение ваше будет запущено на PaaSе. Я про это рассказываю в восьмом модуле курса. Если у вас много крутейших специалистов, вы Apple, и вы хотите иметь полный контроль над всем железом, то вы ближе к IaaSу или к on-premices собственному датацентру.

Подробнее..

Перевод Terraform в AWS несколько аккаунтов и другие хитрости

19.03.2021 08:14:45 | Автор: admin


В этой статье поговорим о нюансах использования Terraform от HashiCorp, в частности о том, как использовать Terraform при управлении несколькими аккаунтами Amazon Web Services (так делают все чаще из-за размера организации или предпочтений команды DevOps). По сути, AWS сами намекают клиентам, что неплохо было бы использовать несколько аккаунтов, и недавно даже выпустили для этого несколько сервисов.


Зачем нужно несколько аккаунтов AWS?


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


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


На практике крупные организации из-за своих размеров уже используют несколько аккаунтов AWS, но эти аккаунты никак не связаны. Это серьезно усложняет жизнь отделам закупок на каждый аккаунт AWS нужен отдельный счет, причем организация может группировать счета в соответствии со своими внутренними правилами или нормативными требованиями. Чтобы упростить работу, можно использовать AWS Organizations для управления иерархией аккаунтов и объединения счетов по группам. Недавно AWS представили AWS Control Tower для подготовки новых аккаунтов с предустановленным набором ресурсов и централизованным управлением всеми аккаунтами.


Новый тренд


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


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


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


Инфраструктура как код с несколькими аккаунтами


Управление ресурсами в разных аккаунтах


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


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


provider aws {region = us-east-1}

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


provider aws {  region = us-east-1  assume_role {    role_arn = arn:aws:iam::123456789012:role/iac  }}

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


Промежуточная роль для доступа к третьему аккаунту


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



Рис. 1. Схема промежуточной роли для доступа к финальному аккаунту AWS


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


Другие продвинутые стратегии Terraform


Несколько стейтов


Если ресурсов относительно много, можно разделить скрипты Terraform на несколько стейтов особенно при использовании continuous deployment (CD). Управление всеми ресурсами в одном стейте имеет недостатки:


  • Каждый раз, когда мы вносим даже незначительные изменения, мы боимся, что Terraform затронет базовые ресурсы, которые трогать не надо.
  • Ошибочные изменения в базовых ресурсах, примененные вслепую в рамках continuous deployment, могут иметь плачевные последствия.
  • Разрешения IAM, которые нужны для выполнения скрипта Terraform, будут затрагивать самые разные задачи. Их будет больше, чем требуется для CD.
  • На применение изменений нужно очень много времени, потому что Terraform будет собирать стейт всех ресурсов, которыми управляет стейт, даже если в большинстве из них ничего не поменялось.
  • Если при деплойменте произойдет сбой, последствия могут быть обширными.

Обычно базовые ресурсы редко меняются. Речь идет о VPC, подсетях, Transit Gateways, VPN, базах данных RDS и балансировщиках нагрузки. Эти ресурсы принадлежат базовому стейту, который почти не меняется, а если и меняется, то руками человека.


Некоторые ресурсы, наоборот, меняются постоянно. Это инстансы EC2, автоскейлинг группы, сервисы в ECS и EKS. Обычно такие ресурсы деплоятся (или обновляются) через пайплайны CD и помещаются в другой стейт, отдельно от базовых ресурсов. Этот отдельный набор скриптов Terraform будет управлять лишь небольшой, быстро меняющейся группой ресурсов, и вам потребуется гораздо меньше разрешений. Такое разделение стейтов Terraform идеально подойдет для автоматизированных деплоев.


Интересный пример такой конфигурации кластер Kubernetes, управляемый базовым стеком, где деплоями Kubernetes управляет стек CD.


Модули


Terraform упрощает разбивку кода IaC на модули. Просто поместите код в другой каталог и используйте директиву module:


provider aws {region = us-east-1}module mymodule {source = ./modules/my_modulevariable1 = value1variable2 = value2}

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


Модули Terraform позволяют соблюдать принцип DRY (Dont Repeat Yourself не повторяйся). Но все равно остается шаблонный код (определения в бэкенде и вызовы к самим модулям), который нельзя поместить в модуль.


Окружения


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


Terraform предлагает воркспейсы, но прежде чем применить изменения, мы должны переключиться с одного на другой (например, с продакшена на стейджинг). Если делать это вручную, высок риск, что однажды кто-нибудь забудет сменить воркспейс и задеплоит код не в то окружение. Очевидно, что последствия могут быть катастрофическими.


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


Заключение


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


С помощью советов в этой статье можно создать аккуратный код Terraform в соответствии с принципами DRY.

Подробнее..

Перевод Реализуем бессерверный API с AWS Gateway и Lambda

01.04.2021 16:06:37 | Автор: admin


Без API не обходится ни одно веб-приложение. Для их разработки используются разные методы. Сейчас, например, набирает популярность бессерверный подход он экономичный, масштабируемый и относительно простой. Как ведущий провайдер бессерверных вычислений Amazon Web Services (AWS) вносит огромный вклад в бессерверную разработку. Здесь мы обсудим общие концепции реализации API с помощью AWS Lambda и других сервисов AWS.


Почему именно AWS Lambda?


AWS Lambda это сервис AWS, который отвечает за выполнение определенных функций в ответ на триггеры, то есть события в приложении. Это могут быть HTTP-вызовы, события в других сервисах AWS, например S3, Kinesis или SNS, или повторяющиеся запланированные события. Функции выполняются в эфемерных контейнерах, подготовкой и масштабированием которых занимается AWS, так что разработчики избавлены от хлопот, связанных с инфраструктурой.


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


Роль API Gateway


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


HTTP API


API Gateway включает множество функций и интеграций. В какой-то момент в Amazon поняли, что разработчикам, которые используют бессерверные вычисления, обычно не нужно столько всего. Скорее, они предпочли бы в целом упростить процесс реализации. Наверное, поэтому в конце 2019 года AWS объявили о новых HTTP API, облегченной версии API Gateway, которая существенно упрощает разработку, повышает производительность и снижает расходы для бессерверных API. Несмотря на свою простоту, HTTP API поддерживают такие важные фичи, как настройка CORS для всех конечных точек, интеграция JWT, кастомные домены и соединения с VPC.


Принципы бессерверных API


Чтобы разобраться с главными принципами реализации бессерверных API, рассмотрим лаконичный пример простого приложения виртуальной доски, состоящий из двух конечных точек: POST для записи сообщений и GET для извлечения трех последних сообщений. Рассмотрим и другие возможные функции (параметры пути, CORS и авторизаторы), но постараемся не усложнять финальную реализацию.


AWS DynamoDB


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


AWS Serverless Application Model


Для реализации вам понадобится аккаунт AWS, а также установленный и настроенный фреймворк AWS Serverless Application Model (SAM). SAM это инструмент для создания, обновления и администрирования бессерверных приложений и всех ресурсов, которые нужны ему для работы. С AWS SAM мы не создаем каждый сервис вручную на веб-консоли мы просто описываем все, что нам нужно, в специальном файле шаблона.
После установки CLI переходим в нужный каталог и выполняем команду:


$ sam init -r nodejs12.x -n whiteboard
Инициализация нового проекта


Выбираем первую опцию и нажимаем Quick Start from Scratch (Быстрый запуск с нуля). Создается каталог нашей доски с минимумом установочных файлов.


Определяем необходимые ресурсы


Сначала открываем файл template.yml и удаляем все, что находится под разделом Resources. Прежде чем перейти к самому API, создаем дополнительные ресурсы. Определяем таблицу DynamoDB, где будут храниться сообщения:


Resources:  BoardMessagesTable:      Type: AWS::DynamoDB::Table      Properties:        TableName: board-messages-table        AttributeDefinitions:          - AttributeName: partKey            AttributeType: S          - AttributeName: createdAt            AttributeType: N        KeySchema:          - AttributeName: partKey            KeyType: HASH          - AttributeName: createdAt            KeyType: RANGE        ProvisionedThroughput:          ReadCapacityUnits: 5          WriteCapacityUnits: 5

Объявление таблицы DynamoDB


AWS создает таблицу DynamoDB, где атрибутом partKey будет ключ партиции, одинаковый для всех записей, а атрибутом createdAt будет ключ диапазона для сортировки по метке времени. Можно добавить в записи другие ключи и значения, но определять их необязательно.


Теперь в том же файле, сразу под предыдущим определением, объявим HTTP API, с которым будут связаны все будущие конечные точки и функции.


BoardHttpApi:    Type: AWS::Serverless::HttpApi    Properties:      StageName: Test      CorsConfiguration: True

Объявление HTTP API


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


Определяем функции обработчиков API


Наконец, определив все API, давайте объявим две функции, связанные с конкретными конечными точками.


PostMessageFunction:      Type: AWS::Serverless::Function      Properties:        Handler: src/handlers/postMessage.handler        Runtime: nodejs12.x        MemorySize: 128        Timeout: 5        Events:          PostMessage:            Type: HttpApi            Properties:              ApiId: !Ref BoardHttpApi              Method: POST              Path: /messages        Policies:          - AmazonDynamoDBFullAccess  GetMessagesFunction:      Type: AWS::Serverless::Function      Properties:        Handler: src/handlers/getMessages.handler        Runtime: nodejs12.x        MemorySize: 128        Timeout: 5        Events:          GetMessages:            Type: HttpApi            Properties:              ApiId: !Ref BoardHttpApi              Method: GET              Path: /messages        Policies:          - AmazonDynamoDBFullAccess

Объявление обработчиков для запросов POST и GET


Тут все понятно: две функции, одна из которых будет вызываться при запросе POST к пути /messages, а другая при запросе GET к тому же пути. У обеих функций есть ограничения на 128 МБ оперативки и пятисекундный таймаут. Код функций находится в файлах postMessage.js и getMessage.js в каталоге /src/handlers/. Создадим их прямо сейчас. (Мы предоставили полный доступ к DynamoDB в разделе Policies каждой функции, чтобы упросить код. В реальном проекте доступ нужно будет настроить более тонко).


Написание функций


Идем в каталог /src/handlers и создаем файлы со следующим содержимым:


postMessage.js


const AWS = require('aws-sdk');const dynamodb = new AWS.DynamoDB();exports.handler = async (event) => {  const { body } = event;  try {    const { author, text } = JSON.parse(body);    if (!author || !text) {      return {        statusCode: 403,        body: 'author and text are required!'      }    }    await dynamodb.putItem({      TableName: 'board-messages-table',      Item: {        msgId: { S: 'board' },        author: { S: author },        text: { S: text },        createdAt: { N: String(Date.now()) } // still expects string!      }    }).promise();    return {       statusCode: 200,       body: 'Message posted on board!',    }  } catch (err) {    return {       statusCode: 500,       body: 'Something went wrong :(',    }  }};

Код обработчика запросов POST


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


getMessages.js


const AWS = require('aws-sdk');const dynamodb = new AWS.DynamoDB();exports.handler = async () => {  try {    const result = await dynamodb.query({      TableName: 'board-messages-table',      KeyConditionExpression: 'partKey = :partKey',      ScanIndexForward: false,      Limit: 3,      ExpressionAttributeValues: {':partKey': { S: 'board'}}    }).promise();    return {      statusCode: 200,      headers: {        'Content-Type': 'application/json',      },      body: JSON.stringify(result.Items),    }  } catch (err) {    console.log(err);    return {      statusCode: 500,      body: 'Something went wrong :(',    }  }};

Код обработчика запросов GET


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


Развёртывание


Деплоить с AWS SAM легко достаточно одной команды с несколькими введенными значениями. Переходим в root-каталог проекта и выполняем команду:


$ sam deploy --guided

Команда развертывания


Нас попросят ввести имя приложения и выбрать регион AWS, а еще подтвердить несколько действий:



Указание и подтверждение параметров


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



Список создаваемых ресурсов их статусы


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



URL для конечной точки root API


Тестируем API


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


curl -d '{"author":"name", "text":"Message text"}' -H "Content-Type: application/json" -X POST https://your-api-id.execute-api.your-region.amazonaws.com/test/messages

Выполнение запроса POST в curl


Отправляем несколько запросов с разными сообщениями. Если все нормально, в консоли отобразится Message posted on board! (Сообщение опубликовано на доске) без ошибок.


Чтобы извлечь последнее сообщение, выполним простую команду, даже короче предыдущей:


curl https://your-api-id.execute-api.your-region.amazonaws.com/test/messages

Выполнение запроса GET в curl


Вот и все. Мы создали простой HTTP API с AWS Lambda и AWS SAM. Конечно, в реальном проекте нужно будет больше функций и конфигураций, но принцип будет тот же: определяем ресурсы, определяем конфигурации, пишем код и запускаем деплой.


Подключение мониторинга Thundra


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


Можно подключить мониторинг Thundra к только что созданным функциям Lambda (см. краткое руководство). После подключения Thundra вам нужно будет инструментировать функции Lambda postMessage и getMessages, чтобы просмотреть подробную информацию о каждом вызове и получить общую картину приложения.


Выбираем функции в списке, нажимаем сначала кнопку Instrument, а затем OK.



Подтверждение инструментирования функции Lambda


Пробуем сделать несколько запросов к API, возвращаемся на дашборд Thundra, нажимаем на имя функции и выбираем вызовы из списка. Здесь мы видим время, производительность, входные и выходные данные функции и т. д. Это очень полезно при отладке API в реальных проектах.



Сведения об одном вызове


Если вы используете бессерверные вычисления в сложных проектах с разными сервисами AWS или других вендоров, вам определенно пригодится функция Unique Tracing, которая существенно упрощает устранение неполадок и отладку приложения.


Стоит ли использовать HTTP API?


С помощью HTTP API с AWS Lambda можно создавать высокопроизводительные и экономичные API. Хоть это и облегченная версия API Gateway REST API, она обладает всем необходимым функционалом и покрывает 90% нужд разработчиков. HTTP API не поддерживают некоторые полезные функции, вроде кэширования, валидации схем и трансформации ответов.


Кэширование вам, скорее всего, не пригодится, потому что HTTP API работают гораздо быстрее старых REST API, а валидацию и трансформацию можно выполнять на уровне кода функции.
Если у ваших разработчиков нет других причин отказаться от HTTP API, можете с уверенностью их использовать. Обычно бессерверная транзакция начинается с вызова API, а отслеживать асинхронный поток событий не так-то просто. В таких ситуациях используйте комплексную функцию распределенного трейсинга в Thundra. Thundra предоставляет 250 тысяч запросов в месяц бесплатно вполне достаточно для маленьких проектов или стартапов.

Подробнее..

Nuke настраиваем сборку и публикацию .NET-проекта

15.01.2021 12:16:15 | Автор: admin

Введение

В настоящее время существует множество систем CI/CD. У всех есть определенные достоинства и недостатки и каждый выбирает себе наиболее подходящую под проект. Цель данной статьи - познакомить с Nuke на примере web-проекта, использующего уходящий на покой .NET-Framework с прицелом дальнейшего обновления до .NET 5. В проекте уже используется сборщик Fake, но возникла необходимость его обновления и доработки, что в итоге привело переходу на Nuke.

Исходные данные

  • Web-проект, написанный на C#, в основе которого лежит .NET-Framework 4.8, Razor Pages + frontend скрипты на TypeScript, компилирующиеся в JS-файлы.

  • Сборка и публикация приложения с помощью Fake 4.

  • Хостинг на AWS (Amazon Web Services)

  • Окружения: Production, Staging, Demo

Цель

Необходимо обновить систему сборки, обеспечивая при этом расширяемость и гибкую настройку. Также нужно обеспечить настройку конфигурации в файле Web.config под заданное окружение.
Я рассматривал разные варианты систем сборки и в итоге выбор пал на Nuke, так как он довольно простой и по сути представляет собой консольное приложение расширяемое за счёт пакетов. Кроме того, Nuke довольно динамично развивается и хорошо документирован. Плюсом идёт наличие плагина к IDE (среда разработки - Rider). Я отказался перехода на Fake 5 из-за стремления обеспечить языковое единство проекта и снизить порог входа, вновь пришедшим разработчикам. Кроме того, скрипты сложнее отлаживать. Cake, Psake также отбросил из-за "скриптовости".

Подготовка

Nuke имеет dotnet tool, с помощью которого добавляется build-проект. Для начала установим его.

$ dotnet tool install Nuke.GlobalTool --global

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

В результате добавился проект _build

В каталоге boot лежат shell-скрипты для запуска сборщика.
Класс Build содержит основной код сборщика. Схема работы классическая - запускается цепочка взаимозависимых Target-ов. Вся информация выводится о процессе сборки выводится к консоль с помощью методов класса Logger. Например:

Logger.Info($"Starting build for {ApplicationForBuild} using {BuildEnvironment} environment");


Существует возможность передавать опции сборки через аргументы командной стройки. Для этого к полю класса Build применяется аттрибут [Parameter]. Ниже я приведу пример использования.

Написание кода сборщика

В моем случае сборка и публикация проекта состоит нескольких этапов

  1. Восстановление Nuget-пакетов

  2. Сборка проекта

  3. Публикация приложения

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

[Parameter("Configuration to build - Default is 'Release'")]readonly Configuration Configuration = Configuration.Release;[Parameter(Name="application")]readonly string ApplicationForBuild;[Parameter(Name="environment")]public readonly string BuildEnvironment;

Конфигуратор создается перед запуском сборки. Для этого я переопределяю метод базового класса OnBuildInitialized, который вызывается после того как, приведённые выше, параметры проинициализированы. Существует ещё несколько виртуальных методов в классе NukeBuild с префиксом On, вызываемые после определенных событий (например, старт/окончание сборки).

Код
protected override void OnBuildInitialized(){  ConfigurationProvider = new ConfigurationProvider(ApplicationForBuild, BuildEnvironment, RootDirectory);  string configFilePath = $"./appsettings.json";  if (!File.Exists(configFilePath))  {  throw new FileNotFoundException($"Configuration file {configFilePath} is not found");  }  string configFileContent = File.ReadAllText(configFilePath);  if (string.IsNullOrEmpty(configFileContent))  {  throw new ArgumentNullException($"Config file {configFilePath} content is empty");  }  /* Настойка конфигурации typescript */  ToolsConfiguration = JsonConvert.DeserializeObject<ToolsConfiguration>(configFileContent);  if (ToolsConfiguration == null || string.IsNullOrEmpty(ToolsConfiguration.TypeScriptCompilerFolder))  {  throw new ArgumentNullException($"Typescript compiler path is not defined");  }  base.OnBuildInitialized();}
Код конфигурации
public class ApplicationConfig{  public string ApplicationName { get; set; }  public string DeploymentGroup { get; set; }  /* Опции для замены в файле Web.config */  public Dictionary<string, string> WebConfigReplacingParams { get; set; }  public ApplicationPathsConfig Paths { get; set; }}
Непосредственно конфигуратор
public class ConfigurationProvider{  readonly string Name;  readonly string DeployEnvironment;  readonly AbsolutePath RootDirectory;  ApplicationConfig CurrentConfig;  public ConfigurationProvider(string name,                                string deployEnvironment,                                AbsolutePath rootDirectory)  {    RootDirectory = rootDirectory;    DeployEnvironment = deployEnvironment;    Name = name;  }  public ApplicationConfig GetConfigForApplication()  {    if (CurrentConfig != null) return CurrentConfig;    string configFilePath = $"./BuildConfigs/{Name}/{DeployEnvironment}.json";    if (!File.Exists(configFilePath))    {    throw new FileNotFoundException($"Configuration file {configFilePath} is not found");    }    string configFileContent = File.ReadAllText(configFilePath);    if (string.IsNullOrEmpty(configFileContent))    {    throw new ArgumentNullException($"Config file {configFilePath} content is empty");    }    CurrentConfig = JsonConvert.DeserializeObject<ApplicationConfig>(configFileContent);    CurrentConfig.Paths = new ApplicationPathsConfig(RootDirectory, Name, CurrentConfig.ApplicationName);    return CurrentConfig;  }}

Восстановление Nuget-пакетов

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

Код
Target Restore => _ => _    .DependsOn(Clean)    .Executes(() =>    {    NuGetTasks.NuGetRestore(config =>    {    config = config    .SetProcessToolPath(RootDirectory / ".nuget" / "NuGet.exe")    .SetConfigFile(RootDirectory / ".nuget" / "NuGet.config")    .SetProcessWorkingDirectory(RootDirectory)    .SetOutputDirectory(RootDirectory / "packages");    return config;    });    });

Сборка проекта

Код собирается в два шага. Сначала компилируется .NET-проект, далее TypeScript-файлы компилируются в JavaScript-код.

Код
Target Compile => _ => _  .DependsOn(Restore)  .Executes(() =>  {  AbsolutePath projectFile = ApplicationConfig.Paths.ProjectDirectory.GlobFiles("*.csproj").FirstOrDefault();    if (projectFile == null)    {    throw new ArgumentNullException($"Cannot found any projects in {ApplicationConfig.Paths.ProjectDirectory}");    }    MSBuild(config =>    {      config = config      .SetOutDir(ApplicationConfig.Paths.BinDirectory)      .SetConfiguration(Configuration) //указываем режим сборки: Debug/Release      .SetProperty("WebProjectOutputDir", ApplicationConfig.Paths.ApplicationOutputDirectory)      .SetProjectFile(projectFile)      .DisableRestore(); //так как мы восстановили пакеты на предыдущем этапе, то отключаем восстановление на этапе сборки      return config;    });    /* Запускаем tsc как отдельный процесс. Копируем файлы в каталог для публикации */    IProcess typeScriptProcess = ProcessTasks.StartProcess(@"node",$@"tsc -p {ApplicationConfig.Paths.ProjectDirectory}", ToolsConfiguration.TypeScriptCompilerFolder);    if (!typeScriptProcess.WaitForExit())    {    Logger.Error("Typescript build is failed");    throw new Exception("Typescript build is failed");    }  CopyDirectoryRecursively(ApplicationConfig.Paths.TypeScriptsSourceDirectory, ApplicationConfig.Paths.TypeScriptsOutDirectory, DirectoryExistsPolicy.Merge, FileExistsPolicy.Overwrite);  });

Публикация приложения

Проводится также в несколько этапов: подготовка артефактов и собственно публикация.

Сначала идёт трансформация конфигурации в файле Web.config под соответствующее окружение. Она заключается в замене значений определенных опций. Необходимые значения считываются из json-файла конфигурации окружения.

Все файлы архивируются и отправляются через CodeDeploy на сервер. Для работы с AWS я подключил NuGet-пакеты AWSSDK: AWSSDK.Core, AWSSDK.S3, AWSSDK.CodeDeploy. Я написал обертки над вызовами AWS CodeDeploy. Они особого интереса не предоставляют и служат скорее цели сокращения объема кода в классе Build.

Код
Target Publish => _ => _  .DependsOn(Compile).Executes(async () =>    {    PrepareApplicationForPublishing();          await PublishApplicationToAws();    });void PrepareWebConfig(Dictionary<string, string> replaceParams){  if (replaceParams?.Any() != true) return;  Logger.Info($"Setup Web.config for environment {BuildEnvironment}");  AbsolutePath webConfigPath = ApplicationConfig.Paths.ApplicationOutputDirectory / "Web.config";  if (!FileExists(webConfigPath))  {  Logger.Error($"{webConfigPath} is not found");  throw new FileNotFoundException($"{webConfigPath} is not found");  }  XmlDocument webConfig = new XmlDocument();  webConfig.Load(webConfigPath);  XmlNode settings = webConfig.SelectSingleNode("configuration/appSettings");  if (settings == null)  {  Logger.Error("Node configuration/appSettings in the config is not found");  throw new ArgumentNullException(nameof(settings),"Node configuration/appSettings in the config is not found");  }  foreach (var newParam in replaceParams)  {  XmlNode nodeForChange = settings.SelectSingleNode($"add[@key='{newParam.Key}']");  ((XmlElement) nodeForChange)?.SetAttribute("value", newParam.Value);  }  webConfig.Save(webConfigPath);}void PrepareApplicationForPublishing(){AbsolutePath specFilePath = ApplicationConfig.Paths.PublishDirectory / AppSpecFile;AbsolutePath specFileTemplate = ApplicationConfig.Paths.BuildToolsDirectory / AppSpecTemplateFile;PrepareWebConfig(ApplicationConfig.WebConfigReplacingParams);DeleteFile(ApplicationConfig.Paths.ApplicationOutputDirectory);CopyDirectoryRecursively(ApplicationConfig.Paths.ApplicationOutputDirectory, ApplicationConfig.Paths.PublishDirectory / DeployAppDirectory,DirectoryExistsPolicy.Merge, FileExistsPolicy.Overwrite);CopyDirectoryRecursively(ApplicationConfig.Paths.BuildToolsDirectory / DeployScriptsDirectory, ApplicationConfig.Paths.TypeScriptsOutDirectory,DirectoryExistsPolicy.Merge, FileExistsPolicy.Overwrite);CopyFile(ApplicationConfig.Paths.BuildToolsDirectory / AppSpecTemplateFile, ApplicationConfig.Paths.PublishDirectory / AppSpecFile, FileExistsPolicy.Overwrite);CopyDirectoryRecursively(ApplicationConfig.Paths.BuildToolsDirectory / DeployScriptsDirectory, ApplicationConfig.Paths.PublishDirectory / DeployScriptsDirectory,DirectoryExistsPolicy.Merge, FileExistsPolicy.Overwrite);Logger.Info($"Creating archive '{ApplicationConfig.Paths.ArchiveFilePath}'");CompressionTasks.CompressZip(ApplicationConfig.Paths.PublishDirectory, ApplicationConfig.Paths.ArchiveFilePath);}async Task PublishApplicationToAws(){  string s3bucketName = "";  IAwsCredentialsProvider awsCredentialsProvider = new AwsCredentialsProvider(null, null, "");  using S3FileManager fileManager = new S3FileManager(awsCredentialsProvider, RegionEndpoint.EUWest1);  using CodeDeployManager codeDeployManager = new CodeDeployManager(awsCredentialsProvider, RegionEndpoint.EUWest1);  Logger.Info($"AWS S3: upload artifacts to '{s3bucketName}'");  FileMetadata metadata = await fileManager.UploadZipFileToBucket(ApplicationConfig.Paths.ArchiveFilePath, s3bucketName);  Logger.Info(  $"AWS CodeDeploy: create deploy for '{ApplicationConfig.ApplicationName}' in group '{ApplicationConfig.DeploymentGroup}' with config '{DeploymentConfig}'");  CodeDeployResult deployResult =  await codeDeployManager.CreateDeployForRevision(ApplicationConfig.ApplicationName, metadata, ApplicationConfig.DeploymentGroup, DeploymentConfig);  StringBuilder resultBuilder = new StringBuilder(deployResult.Success ? "started successfully\n" : "not started\n");  resultBuilder = ProcessDeloymentResult(deployResult, resultBuilder);  Logger.Info($"AWS CodeDeploy: deployment has been {resultBuilder}");  DeleteFile(ApplicationConfig.Paths.ArchiveFilePath);  Directory.Delete(ApplicationConfig.Paths.ApplicationOutputDirectory, true);  string deploymentId = deployResult.DeploymentId;  DateTime startTime = DateTime.UtcNow;  /* Ожидаем когда деплой завершится и выводим сообщение */  do  {  if(DateTime.UtcNow - startTime > TimeSpan.FromMinutes(30)) break;  Thread.Sleep(3000);  deployResult = await codeDeployManager.GetDeploy(deploymentId);  Logger.Info($"Deployment proceed: {deployResult.DeploymentInfo.Status}");  }  while (deployResult.DeploymentInfo.Status == DeploymentStatus.InProgress  || deployResult?.DeploymentInfo.Status == DeploymentStatus.Created  || deployResult?.DeploymentInfo.Status == DeploymentStatus.Queued);  Logger.Info($"AWS CodeDeploy: deployment has been done");}

Заключение

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


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

Подробнее..

CloudWatch и Lambda, или Как я перестал бояться и полюбил AWS

23.04.2021 14:18:12 | Автор: admin

Облачные провайдеры это реактор, где вместо обогащённого урана используется твой кошелёк. В позапрошлом году наша компания начала активно применять облака и мы в полной мере ощутили это на себе: несколько команд разрабатывали отдельные продукты, и для большинства тестов запускались виртуальные мощности в AWS. Мы с коллегами получили сертификаты от Amazon, и это, вместе с наглядностью происходящего, Free Tier и Soft Limitами, создавало ложное чувство спокойствия за свой бюджет. А когда этому чувству поддаёшься, получаешь локальный Чернобыль.

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

Почему настройка оповещений это плацебо

Первый способ, на который указывает сам AWS это настройка бюджетов AWS Budgets и оповещений из них. Да, здесь есть очевидные плюсы: это решение очень легко настроить, а сервис предупреждает в случае превышения текущего или прогнозируемого бюджета. С сентября 2020 г. он даже научился прогнозировать потребление и отправку событий в Amazon SNS.

Но объективно это просто ещё одна загорающаяся лампочка: оповещение может прийти на почту в середине ночи, а узнаёшь об этом только в понедельник утром. К тому же, по умолчанию AWS Budgets ничего не делает после того как заметил превышение. Он отлично подходит для контроля конкретных задач (например, отмеряет скорость расходования средств на проде), но среагирует слишком поздно, если у нас рядом будут работать запущенные по ошибке или безымянные виртуальные машины. Не подойдёт.

Как взять под контроль облачный ядерный реактор

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

Я решил, что нужно где-то разместить логику реагирования и дёргать за различные API в облаке. Проще всего это сделать в AWS Lambda, так как Serverless может работать бесплатно, логика реагирования оформляется как на NodeJS, так и на Python, а простота API-вызовов из облака и ролевая модель доступа сокращают время на тестирование такого решения.

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

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

Какие есть инструменты для контроля трат на AWS

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

  • Cost Explorer даёт подробную разбивку по сервисам, но единственное, что он показывает, это сколько аккаунт уже успел потратить. Ничего не знает про запущенные в данный момент виртуальные мощности, но с его помощью можно оптимизировать траты.

  • Budgets внутри Cost Explorer. С сентября 2020 г. он научился определять Usage в часах, но всё ещё не даёт ответа, как идентифицировать забытые сущности.

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

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

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

Накопление данных Lambda + S3

Так как сложные варианты мне не подошли, я остановился на простом: решил накапливать знание о времени работы каждого инстанса самостоятельно, благо хранение файлов это тривиальная задача для Lambda + S3.

Для упрощения тестирования и читаемости кода разобьём задачу между несколькими Lambda:

  • отдельно собираем информацию по запущенным инстансам;

  • решаем, какие инстансы заслуживают выключения, а какие нет;

  • выключаем ненужные инстансы.

Оркестратором простой цепочки Lambda я сделал Step Functions, который может запускаться по расписанию из CloudWatch.

Пример решения

Файлы для Proof of Concept вы можете найти по ссылке на GitHub, а ниже я распишу, что делает этот код. В жизни он дорабатывался под нужды команд и использовался до тех пор, пока мы не обучили достаточное количество сотрудников соблюдать правила работы с облаком.

Что тут происходит?

Каждые 5 минут CloudWatch отправляет заготовленный вызов в Step Functions, который управляет последовательным запуском четырёх Lambda-функций. Каждая Lambda-функция исполняет код на JavaScript (версии Node.js 10.x), использует сервисы EC2, Config или S3, и завершает свою работу передачей JSON в следующую Lambda. Исполнение скрипта завершается записью логов в CloudWatch Logs.

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

CloudWatch Event > Step Function > 4 Lambda functions > CloudWatch Logs

  1. Get List of Working Instances получает список работающих инстансов и передает его через JSON в следующую Lambda-функцию

  2. Update Budget Usage делает много вещей, но главное обновляет данные файла в S3-хранилище.

  3. Terminate Instances выключает инстансы, которые превышают бюджет или нас не устраивают.

Как устанавливать?

После размещения кода и настройки ролей в Lambda-функциях необходимо составить схему работы через Step Functions, а также привязать событие CloudWatch Event Rule, которое будет запускать систему каждые 5 минут.

Как бы я подошёл к этой проблеме сейчас

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

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

Если бы я сейчас начал заново решать проблему избыточного времени работы, то в S3 вместо файла бюджета оказался бы файл с договорённостями по использованию тегов. Lambda вместо оценки времени работы немедленно выключала бы все мощности, не подходящие по тегам. А контроль за расходами перешёл бы в связку AWS Budget и SNS с той же Lambda, управляющей их отключением.

Подробнее..

Пишем мессенджер на Vue в облаке Amazon

16.01.2021 20:09:22 | Автор: admin

Разберем, как использовать облачный сервис Amazon для созданиямессенджера Chattyмногопользовательского чат-приложения в реальном времени с одной комнатой с помощью фреймворка Vue иAWS Amplify. Настроим регистрацию пользователей и хранение данных.

Темы, которые мы рассмотрим:

  • Аутентификация

  • GraphQL API с AWS AppSync

  • Настроить Amplify DataStore

  • Развертывание через консоль Amplify

  • Удаление сервисов

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

Результат можно увидеть тут: https://master.d58xs5f4j0v44.amplifyapp.com/

Предварительные условия:

  • Регистрация за $1 в сервисах Amazon AWS уже произведена

  • Бесплатный редактор Visual Studio Code установлен, локализован и установлен npm:

    • Node:14.7.0. VisitNode

    • npm:6.14.7.

npm install -g npm

Начало работы - Создание приложения

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

npm install -g @vue/clivue create amplify-datastore
  • ?Выберитепредустановку: поумолчанию [Vue 2] (babel, eslint)

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

cd amplify-datastore npm run serve

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

Откроем папку проекта C:\Users\Admin\amplify-datastore> в редакторе Visual Studio Code:

Обратите внимание на окончание строк LFОбратите внимание на окончание строк LF

Мы видим шаблон приложения Vue, и оно работает локально.

Остановим его CTRL+C что бы продолжить.

Давайте теперь установим API AWS Amplify и библиотеку AWS Amplify Vue:

npm install --save aws-amplify @aws-amplify/ui-vue moment

Установка интерфейса командной строки AWS Amplify

Далее мы установим интерфейс командной строки AWS Amplify:

npm install -g @aws-amplify/cli

Теперь нам нужно настроить CLI с нашими учетными данными:

amplify configure

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

Здесь мы рассмотримamplify configureнастройку.После входа в консоль AWS продолжайте:

  • Укажите регион AWS:eu-central-1 (Франкфурт)

  • Укажите имя пользователя нового пользователя IAM:ampify-datastore

В консоли AWS нажмитеДалее: Разрешения,Далее: Теги,Далее: ОбзориСоздать пользователя,чтобы создать нового пользователя IAM.Затем вернитесь в командную строку и нажмите Enter.

  • Введите ключ доступа вновь созданного пользователя:

    accessKeyId:(<YOURACCESSKEYID>)secretAccessKey:(<YOURSECRETACCESSKEY>)

  • Имя профиля: поумолчанию

Чтобы просмотреть нового созданного пользователя IAM, перейдите на панель управления по адресуhttps://console.aws.amazon.com/iam/home?region=eu-central-1#/users.Также убедитесь, что ваш регион соответствует вашему выбору.

Инициализация нового проекта

amplify init
  • Введите название проекта:ampifydatastore

  • Введите имя для среды:dev

  • Выберите редактор по умолчанию:Visual Studio Code

  • Выберите тип приложения, которое вы создаетеjavascript

  • Какую среду JavaScript вы используетеvue

  • Путь к исходному каталогу:src

  • Путь ккаталогураспространения:dist

  • Команда сборки:npm run-script build

  • Команда запуска:npm run-script serve

  • Вы хотите использовать профиль AWS? да

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

Теперь интерфейс командной строки AWS Amplify инициировал новый проект, и вы увидите новую папку:ampify.Файлы в этой папке содержат конфигурацию вашего проекта.

<amplify-app>    |_ amplify      |_ .config      |_ #current-cloud-backend      |_ backend      team-provider-info.json

Добавление аутентификации

Чтобы добавить аутентификацию в наш проект Amplify, используем следующую команду:

amplify add auth

При появлении запроса выберите

  • Вы хотите использовать конфигурацию аутентификации и безопасности поумолчанию?:Конфигурация по умолчанию

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

  • Вы хотите настроить дополнительные параметры?Да, я хочу внести дополнительные изменения.

  • Какие атрибуты необходимы для регистрации?(Нажмите <пробел>, чтобы выбрать, <a>, чтобы переключить все, <i>, чтобы инвертировать выделение):Электронная почта

  • Вы хотите включить какие-либо из следующих возможностей?(Нажмите <пробел>, чтобы выбрать, <a>, чтобы переключить все, <i>, чтобы инвертировать выделение):Нет

Чтобы ничего не выбрать, просто нажмитеEnterпоследнюю опцию.

Теперь мы запустим команду push, и облачные ресурсы будут созданы в нашей учетной записи AWS.

amplify push Current Environment: dev| Category | Resource name      | Operation | Provider plugin   || -------- | ------------------ | --------- | ----------------- || Auth     | amplifyappuuid     | Create    | awscloudformation |? Are you sure you want to continue? Yes

Чтобы быстро проверить созданныйпул пользователей Cognito,запустим:

amplify status

Чтобы получить доступ кконсоли AWS Cognitoв любое время, перейдите на панель управления по адресуhttps://console.aws.amazon.com/cognito/.

Настраиваем приложение Vue

Теперь наши ресурсы созданы, и мы можем начать их использовать!

Первое, что нам нужно сделать, это настроить наше приложение Vue, чтобы оно было осведомлено о нашем новом проекте AWS Amplify.Мы можем сделать это, обратившись к автоматически сгенерированномуaws-exports.jsфайлу, который теперь находится в srcпапке.

Чтобы настроить приложение, откройтеmain.jsи добавьте следующий код:

import Vue from 'vue'import App from './App.vue'import Amplify from 'aws-amplify';import '@aws-amplify/ui-vue';import aws_exports from './aws-exports';Amplify.configure(aws_exports);Vue.config.productionTip = falsenew Vue({  render: h => h(App),}).$mount('#app')

Теперь наше приложение готово к использованию сервисов AWS.

Использование компонента аутентификации

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

Чтобы использовать компонент Authenticator, добавьте его вsrc / App.vue:

<template>  <div id="app">    <amplify-authenticator>      <div>        <h1>Hey, {{user.username}}!</h1>        <amplify-sign-out></amplify-sign-out>      </div>    </amplify-authenticator>  </div></template>

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

Чтобы просмотреть всех созданных пользователей, вернитесь напанель управленияCognito поадресуhttps://console.aws.amazon.com/cognito/.

В качестве альтернативы мы также можем использовать

amplify console auth

Доступ к данным пользователя

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

<script>import { AuthState, onAuthUIStateChange } from '@aws-amplify/ui-components'export default {  name: 'app',  data() {    return {      user: { },    }  },  created() {    // authentication state managament    onAuthUIStateChange((state, user) => {      // set current user and load data after login      if (state === AuthState.SignedIn) {        this.user = user;      }    })  }}</script>

Добавление GraphQL API

Чтобы добавить GraphQL API, мы можем использовать следующую команду:

amplify add api

Ответьте на следующие вопросы

  • Пожалуйста, выберите одну из нижеуказанных службGraphQL

  • Укажите имя API:ChattyAPI

  • Выберите тип авторизации по умолчанию дляключаAPIAPI

  • Введите описание ключа API:(пусто)

  • Через сколько дней истечет срок действия ключа API (1-365):7

  • Вы хотите настроить дополнительные параметры для GraphQL API?Да, я хочу внести дополнительные изменения.

  • Настроить дополнительные типы авторизации?N

  • Настроить обнаружение конфликтов?Y

  • Выберите стратегию разрешения по умолчаниюAuto Merge

  • Вы хотите изменить настройки по умолчанию для каждой модели? N

  • У вас есть аннотированная схема GraphQL? N

  • Вам нужно управляемое создание схемы? Y

  • Что лучше всего описывает ваш проект: один объект с полями (например, Todo с идентификатором, именем, описанием)

  • Вы хотите отредактировать схему сейчас? Y

Чтобы ничего не выбрать, просто нажмитеEnter.

При появлении запроса обновите схему до следующего:

type Chatty @model {  id: ID!  user: String!  message: String!  createdAt: AWSDateTime}

Это позволит нам отображать сообщения каждого пользователя вместе с датой и временем создания.

Примечание: не забудьте сохранить изменения в файле схемы!

Затем давайте перенесем конфигурацию в нашу учетную запись:

amplify push
  • Вы уверены что хотите продолжить?да

  • Вы хотите сгенерировать код для недавно созданного GraphQL API?Да

  • Выберите целевой язык генерации кодаjavascript

  • Введите шаблон имени файла для запросов, мутаций и подписокgraphql src / graphql / ** / *. Js

  • Вы хотите сгенерировать / обновить все возможные операции GraphQL - запросы, изменения и подписки?Да

  • Введите максимальную глубину инструкции [увеличьте значение по умолчанию, если ваша схема глубоко вложена]2

Обратите внимание наконечную точку GraphQLиКЛЮЧ API.

На этом шаге был создан новый API AWS AppSync.Используйте команду ниже, чтобы получить доступ к панели управления AWS AppSync.Убедитесь, что ваш регион правильный.

amplify console api
  • Пожалуйста, выберите одну из нижеуказанных службGraphQL

Настроить Amplify DataStore

Установка Amplify DataStore

Далее мы установим необходимые зависимости:

npm install --save @aws-amplify/core @aws-amplify/datastore

Генерация модели данных

Затем мы сгенерируем модели для доступа к нашим сообщениям из нашегоChattyAPI.

amplify codegen models

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

Теперь интерфейс командной строки AWS Amplify сгенерировал необходимые модели данных, и вы увидите новую папку в своем источнике:models.Файлы в этой папке содержат классы и схему вашей модели данных.

<amplify-app>    |_ src      |_ models

Самые нетерпеливые могут заглянуть в репозиторий проекта https://github.com/lazy-fox-code/amplify-datastore и уточнить куда какой код добавлять. Основная логика приложения описывается в App.vue и следующие разделы будут разбирать именно этот файл.

Структура App.vue содержит шаблон <template> в котором присутствуют блоки <divid="app"> с формами, кнопками, авторизацией и прочими деталями приложения. Затем идет раздел <script> в котором импортируются и применяются модели и методы приложения. Затем следуют стили оформления приложения.

Создание сообщения

Теперь, когда GraphQL API и модели данных созданы, мы можем начать с ними взаимодействовать!

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

import { DataStore } from "@aws-amplify/datastore";import { Chatty } from "./models";await DataStore.save(new Chatty({  user: "amplify-user",  message: "Hi everyone!",  createdAt: new Date().toISOString()}))

Это создаст запись локально в вашем браузере и синхронизирует ее в фоновом режиме с помощью базового API GraphQL.

Запрос данных

Давайте теперь посмотрим, как мы можем запрашивать данные с помощью Amplify DataStore.Чтобы запросить нашу модель данных, мы будем использовать запрос и предикат, чтобы указать, что нам нужны все записи.

import { DataStore, Predicates } from "@aws-amplify/datastore";import { Chatty } from "./models";const messages = await DataStore.query(Chatty, Predicates.ALL);

Это вернет массив сообщений, которые мы можем отобразить в нашем пользовательском интерфейсе.

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

Найдите все поддерживаемые фильтры вразделе "Запрос с предикатами"

Создание UI

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

<template>  <div v-for="message of sorted" :key="message.id">    <div>{{ message.user }} - {{ moment(message.createdAt).format('YYYY-MM-DD HH:mm:ss')}})</div>    <div>{{ message.message }}</div>  </div></template><script>import { Auth } from "aws-amplify";import { DataStore, Predicates } from "@aws-amplify/datastore";import { Chatty } from "./models";import moment from "moment";export default {  name: 'app',  data() {    return {      user: {},      messages: [],    }  },  computed: {    sorted() {      return [...this.messages].sort((a, b) => -a.createdAt.localeCompare(b.createdAt));    }  },  created() {    this.currentUser();  },  methods: {    moment: () => moment(),    currentUser() {      Auth.currentAuthenticatedUser().then(user => {        this.user = user;        this.loadMessages();      });    },    loadMessages() {      DataStore.query(Chatty, Predicates.ALL).then(messages => {        this.messages = messages;      });    },  }}</script>

Создание сообщения

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

<template>  <form v-on:submit.prevent>    <input v-model="form.message" placeholder="Enter your message..." />    <button @click="sendMessage">Send</button>  </form></template><script>export default {  data() {    return {      form: {},    };  },   methods: {    sendMessage() {      const { message } = this.form      if (!message) return;      DataStore.save(new Chatty({        user: this.user.username,        message: message,        createdAt: new Date().toISOString()      })).then(() => {        this.form = { message: '' };        this.loadMessages();      }).catch(e => {        console.log('error creating message...', e);      });    },  }}</script>

Удаление всех сообщений

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

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

DataStore.delete(Chatty, Predicates.ALL).then(() => {  console.log('messages deleted!');});

Подписки GraphQL

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

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

Когда компонент будет уничтожен, мы откажемся от подписки, чтобы избежать утечки памяти.

<script>export default {  data() {    return {      subscription: undefined;    };  },  created() {    //Subscribe to changes    this.subscription = DataStore.observe(Chatty).subscribe(msg => {      console.log(msg.model, msg.opType, msg.element);      this.loadMessages();    });  },   destroyed() {    if (!this.subscription) return;    this.subscription.unsubscribe();  },}</script>

Развертывание через консоль Amplify

Мы рассмотрели развертывание через категорию хостинга Amplify CLI, но что, если нам нужно непрерывное развертывание CI/CD?Для этого мы можем использоватьконсоль Amplifyдля развертывания приложения.

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

git initgit remote add origin git@github.com:username/project-name.gitgit add .git commit -m 'initial commit'git push origin master

Затем мы посетим консоль Amplify в нашей учетной записи AWS по адресуhttps://eu-central-1.console.aws.amazon.com/amplify/home.

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

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

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

Наконец, мы можем нажать Сохранить иразвернуть, чтобы развернуть наше приложение!

Теперь мы можем отправлять обновления в Master, чтобы обновить наше приложение.

Удаление сервисов

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

amplify remove authamplify push

Если вы не знаете, какие службы вы в любой момент включили, вы можете запуститьamplify statusкоманду:

amplify status

amplify statusпредоставит вам список ресурсов, которые в настоящее время включены в вашем приложении.

Приложение

Настройка учетной записи AWS

Чтобы пройти этот урок, необходимо создать и активировать учетную запись Amazon Web Services.

Следуйте инструкциямздесь

Устранение неполадок

Сообщение: для идентификатора ключа доступа AWS требуется подписка на сервис

Решение: убедитесь, что вы подписаны на бесплатный план.Подписывайся

Сообщение: TypeError: fsevents не является конструктором

Решение:npm audit fix --force

Поведение: данные не синхронизируются с облаком и / или наоборот

Решение:

amplify update apiamplify push

Убедитесь, что вы ответили на следующие вопросы как

  • Настроить обнаружение конфликтов?Y

  • Выберите стратегию разрешения по умолчаниюAuto Merge

  • Вы хотите изменить настройки по умолчанию для каждой модели?N

Послесловие

Надеюсь данный пост поможет легче пройти квест создания приложения Vue в облаке AWS.

Результат работы двух пользователейРезультат работы двух пользователей

Что дальше?

Конечно у разработчика возникнет ряд вопросов по эффективности использования приложения в среде Amplify. Вот некоторые из них:

5 шагов администрирования приложения5 шагов администрирования приложения

Так же удобно просматривать параметры и настраивать приложение в визуальном инструменте администратора приложения. По мере выполнения команд в консоли пока мы строили приложение, тут появлялись модель данных и API авторизации и содержимого:

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

Подробнее..

Перевод Calico Enterprise обзор

09.02.2021 02:22:17 | Автор: admin

Translation of this article written by John Armstrong on Jan 20, 2021

Вступая в новый год, самое время поразмышлять о достижениях компании Tigera и о том, насколько Calico Enterprise изменилась за последний год и как она стала ведущим решением в сфере безопасности и мониторинга сетей и микросервисов Kubernetes. Опыт работы с пользователями корпоративного класса помог Tigera определить наиболее важные требования пользователей для успешного развертывания кластеров Kubernetes и успешного перехода от пилотных проектов к промышленным проектам. Эти знания помогли Tigera создать систему Calico Enterprise, архитектура которой и представлена ниже. Давайте рассмотрим этот многофункциональный слоёный пирог, снизу вверх.

Архитектура корпоративных решений Calico:

Calico Enterprise является родным для Kube

Cначала следует вспомнить несколько важных вещей. Calico Enterprise - это Kubernetes-native, Kube-native решение, в котором все, что делается, является расширением примитивов Kubernetes. Вся мощь Kubernetes используется путем интеграции с Kubernetes через API плюс путем создания собственного агрегированного API сервера. Операторная модель, взятая целиком из Kubernetes, используется для доступа и управления ресурсами, для выполнения таких функций, как, например, RBAC. Calico Enterprise, будучи родным для Kubernetes, по мере развития Kubernetes автоматически поддерживает взаимно совместимость.

Модель безопасности, работающая всюду

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

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

Подключаемый, ориентированный на будущее Data Plane - Linux, Windows и eBPF

Calico Enterprise с самого начала разрабатывался с полностью подключаемым data planes, поэтому клиенты могут выбрать между разными data planes. Сетевой уровень Kubernetes выделяет три уровня data planes, и все они представлены в Calico Enterprise. Большинство пользователей используют стандартный data plane ядра Linux, потому что они еще не используют последние версии Linux, необходимые для поддержки eBPF. Некоторое количество рабочих приложений выполняется в Windows, и для этих клиентов предлагается то же единое решение, которое работает в Linux. Для пользователей, которые хотят расширить пределы производительности с использованием последних ядер Linux, Calico Enterprise предлагает eBPF data plane. В ближайшие несколько лет неизбежно появятся более быстрые data plane технологии, и Calico Enterprise планирует добавить их поддержку. Это еще один способ, которым Tigera защищает будущие инвестиции клиентов Calico Enterprise и демонстрирует приверженность предоставлять наиболее продвинутые, масштабируемые и надежные решения для пользователей Kubernetes.

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

Управление трафиком North-South

Calico Enterprise обеспечивает контроль безопасности как North-South, так и East-West трафика. В среде Kubernetes North-South принято обозначать трафик, который следует внутрь сети и из сети, а East-West - трафик, следующий внутри сети. Именно на стыке North-South между кластером Kubernetes и внешней средой мы сталкиваемся с наибольшими проблемами безопасности. Используя средства Calico Enterprise для управления политикой (policy) DNS и средства контроля входящего / исходящего доступа (ingress/egress access controls), пользователи контролируют North-South трафик. Корпоративный универсальный межсетевой экран Calico и интеграция с SIEM (Calico Enterprise universal firewall and SIEM integration) - это два метода, которые поддерживают интеграцию существующих средств управления безопасностью предприятия со средой Kubernetes.

Управление трафиком East-West

Контроль трафика East-West ограничивает область разрушения в случае нарушений безопасности, которые приводят к APT (advanced persistent threat). Есть несколько способов, с помощью которых Calico Enterprise помогает настроить эти средства контроля. Подход Calico Enterprise с глубокой защитой (defense-in-depth) обеспечивает защиту на трех уровнях: хост, контейнер / виртуальная машина и приложение. Используя единую структуру политики безопасности, вы настраиваете все эти уровни с помощью декларативной модели. Можно установить очень мелкие элементы управления доступом и фильтровать трафик на уровне протокола приложения, например, по протоколам http, https или MongoDB. Можно выполнять микросегментацию как для контейнерных рабочих нагрузок, так и для рабочих нагрузок виртуальных машин.

Безопасность и постоянное соответствие нормативам (Continuous Compliance)

По мере расширения зоны использования Kubernetes наблюдается потребность в еще более глубоком подходе к защите конфиденциальных данных, подпадающих под действие нормативных требований. Для обеспечения безопасности и постоянного соответствия нормативам (Continuous Compliance) Calico Enterprise обеспечивает шифрование данных в пути (data-in-transit encryption) с лучшей в отрасли производительностью, а также непрерывную отчетность о соответствии политик безопасности и средств управления. В Calico Enterprise есть богатый набор функций обнаружения вторжений (Intrusion Detection), который включает обнаружение различных угроз, настраиваемые оповещения об известных атаках, обнаружение аномалий поведения и приманки (honeypod). Calico Enterprise использует автоматизированный подход к обнаружению вредоносных программ и реагированию на них. Например, Tigera создала алгоритм машинного обучения в Calico Enterprise, который специально нацелен на обнаружение DGA (Domain Generation Algorithm), облегчая группам безопасности обнаружение DGA активности. Calico Enterprise может запускать автоматическое исправление, удаляя мошенническую микросервис из сети за миллисекунды, и генерируя затем рекомендации по политике предотвращения возможных атак.

Мониторинг и устранение неисправностей

Время простоя обходится дорого, а мониторинг распределенных приложений очень сложен. Calico Enterprise динамически генерирует диаграмму сервисов (Service Graph), которая позволяет легко понять, как микросервисы ведут себя и взаимодействуют друг с другом во время работы, упрощая тем самым процесс отладки и мониторинга. Динамическая диаграмма сервисов предоставляет очень богатый набор информации, включая информацию о том, в каких пространствах имен взаимодействуют рабочие нагрузки, подробную DNS информацию , подробные журналы событий (flow logs) для каждого отдельного потока в вашем кластере и то, как оцениваются сетевые политики. Горячие точки производительности автоматически идентифицируются и выделяются, а предупреждения (alerts) выдаются в контексте диаграммы сервисов. Пользуясь этой диаграммой, а также с помощью функции автоматического захвата пакетов, инженеры и программисты могут быстро находить источник проблемы на уровне приложения, процесса и сокета.

Единое управление и автоматизация

Унифицированные элементы управления обеспечивают безопасность и наблюдаемость в средах с несколькими кластерами, несколькими облаками и гибридными облачными средами, а также предоставляют единую панель для обеспечения согласованного применения элементов управления безопасностью. Они также поддерживают непрерывную интеграцию CI / CD для опытных пользователей. Calico Enterprise ввела в действие концепцию уровней политик, которые поддерживают делегирование полномочий по организационной структуре и областям ответственности для различных групп с разными потребностями (безопасность, сеть, платформа, DevOps, SRE, разработка). Уровни политик определяют порядок, в котором оцениваются политики сетевой безопасности, и используются для реализации средств управления безопасностью, которые не могут быть изменены или отменены неавторизованными пользователями. Например, средства контроля доступа в масштабе предприятия, созданные группой безопасности, имеют первостепенное значение и находятся на самом высоком уровне. Уровни политик могут объединяться в несколько кластеров с использованием возможностей централизованного управления Calico Enterprise, что позволяет использовать единое управление безопасностью, применяющиеся ко всем кластерам.

Подробнее..

Мониторим основные сервисы в AWS с Prometheus и exporterами для CloudWatch

12.02.2021 14:21:36 | Автор: admin

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

  1. Как можно настроить сбор данных с endpointов в систему мониторинга?

  2. Если использовать Prometheus, то какие экспортеры использовать и где их можно запускать?

  3. Какие есть варианты готовых алертов для покрытия основных причин аварий/частичной недоступности?

Эта статья в большей степени рассчитана на начинающих инженеров: на примере Prometheus и CloudWatch мы рассмотрим одно из самых простых и понятных решений с помощью cloudwatch_exporter и prometheus_aws_cost_exporter в AWS, напишем для них Helm-чарт и задеплоим его в Kubernetes. (K8s будет выступать удобной площадкой для разворачивания экспортеров.) А также посмотрим, как можно мониторить текущие и ежедневные затраты всей вашей инфраструктуры.


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

У AWS есть отдельные типы инстансов с бюджетами кредитов по CPU и дисков с кредитами по IO. Они позволяют накапливать бюджет кредитов во время сниженной нагрузки и тратить его в том случае, если она резко выросла. Но прогнозировать, когда нагрузка может уйти, проблематично. Поэтому есть риск выработать весь бюджет и перейти на режим ограниченного потребления ресурсов. Данный вариант развития событий сложно диагностировать, так как в мониторинге сервера это напрямую не будет отражено. Поэтому очень полезно мониторить кредиты CPU/IO, чтобы понимать, какое количество кредитов доступно в данный момент, какова динамика их потребления и предвидеть их исчерпание.

Итак, возвращаясь к выбранным инструментам: prometheus_aws_cost_exporter будет использоваться для мониторинга потребления финансов, так как cloudwatch_exporter возвращает информацию только за предыдущий день. Зато cloudwatch_exporter позволяет снимать гораздо больше метрик.

Приступим к непосредственной реализации!

1. Настраиваем IAM

Поскольку рассматривать мы будем два экспортера с немного различным функционалом, потребуются два разных аккаунта в IAM (AWS Identity and Access Management). Ниже представлен список ролей, которые нужны обоим аккаунтам:

  • cloudwatch:ListMetrics

  • cloudwatch:GetMetricStatistics

  • tag:GetResources

Для работы prometheus_aws_cost_exporter требуется больший набор прав: необходимо создать отдельную роль и назначить её пользователю. Для удобства роль можно создать из JSON:

{  "Effect": "Allow",  "Action": [    "cloudwatch:PutMetricData",    "ec2:DescribeVolumes",    "ec2:DescribeTags",    "logs:PutLogEvents",    "logs:DescribeLogStreams",    "logs:DescribeLogGroups",    "logs:CreateLogStream",    "logs:CreateLogGroup",    "ce:GetCostAndUsage"  ],  "Resource": "*"},{  "Effect": "Allow",  "Action": [    "ssm:GetParameter"  ],  "Resource": [    "arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*",    "arn:aws:ce:*:*:/GetCostAndUsage"  ]}

Для учётных записей экспортеров также требуется создать access key ID и secret access key, которые будут передаваться в виде переменных (AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY).

2. Создаем IAM-роли через веб-интерфейс

Авторизуемся в консоли управления AWS и перейдем в раздел IAM, где для примера создадим пользователя под названием cloudwatch_users.

Создание пользователя в IAMСоздание пользователя в IAM

В поле Access Type включим опцию Programmatic access, которая позволит сгенерировать упомянутые access key ID и secret access key (они потребуются для работы с API, сохраните их куда-нибудь в надёжное хранилище). Следующая вкладка Attach existing policies directly, где мы создадим новую политику. Для данной IAM-роли требуются права ListMetrics и GetMetricStatistics.

Создание пользовательского policyСоздание пользовательского policy

Если удобнее создавать роль через API, можно воспользоваться JSON-сниппетом:

{  "Version": "2012-10-17",  "Statement": [    {      "Sid": "VisualEditor0",      "Effect": "Allow",      "Action": [        "cloudwatch:GetMetricStatistics",        "cloudwatch:ListMetrics"      ],      "Resource": "*"    }  ]}

После нажатия на Review policy указываем название для Policy и создаем её (Create policy). Дальнейшие пункты не влияют на функции созданной роли. Однако потребуется вернуться на этап создания IAM-роли, чтобы добавить созданный нами Policy. На самом последнем этапе станут доступны для просмотра значения для переменных AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY, которые надо записать в values.yaml нашего будущего Helm-чарта.

Если вы используете Terraform, то по данной ссылке есть готовый Terraform receipt для создания IAM-роли и пользователей. Ключи API из terraform.tfstate можно получить с помощью jq:

jq '.resources[].instances[].attributes | {(.id): .secret}'

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

3. Helm-чарт для экспортеров

Перейдем к деплою cloudwatch-exporter и cost-exporter в Kubernetes. Потребуется написать очень простой Helm-чарт, который будет состоять из нескольких простых объектов.

В самом начале объявим необходимые переменные в values.yaml:

---aws_access_key_id: <AWS_ACCESS_KEY_ID>aws_secret_access_key: <AWS_SECRET_ACCESS_KEY>region: eu-central-1replicas:  1resources:  requests:    cpu: 1m    memory: 512Mienv:  metric_today_daily_costs: "yes"  metric_yesterday_daily_costs: "yes"  query_period: "1800"  metric_today_daily_usage: "yes"  metric_today_daily_usage_norm: "yes"

Подробнее о содержимом этого файла:

  • В переменных aws_access_key_id и aws_secret_access_key объявляются значения, полученные при создании IAM-роли;

  • region регион, в котором требуется выполнять мониторинг ресурсов;

  • query_period периодичность запроса метрик из AWS (в секундах);

  • metric_today_daily_costs, metric_yesterday_daily_costs, metric_today_daily_usage, metric_today_daily_usage_norm включение/выключение запрашивания метрик затрат (costs) и потребления (usage) за вчера и за сегодня (по умолчанию имеет значение no);

  • Параметры из блока env используются cost-exporterом (на работу cloudwatch-exporter не влияют).

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

apiVersion: apps/v1kind: Deploymentmetadata:  name: cloudwatch-exporterspec:  selector:    matchLabels:      app: cloudwatch-exporter  template:    metadata:      labels:        app: cloudwatch-exporter    spec:      containers:      - name: cloudwatch-exporter        image: prom/cloudwatch-exporter:cloudwatch_exporter-0.9.0        env:        - name: AWS_ACCESS_KEY_ID          value: "{{ .Values.aws_access_key_id }}"        - name: AWS_SECRET_ACCESS_KEY          value: "{{ .Values.aws_secret_access_key }}"        volumeMounts:        - name: config          subPath: config.yml          mountPath: /config/config.yml      volumes:      - name: config        configMap:          name: config

Следующий Deployment (точнее, снова его фрагмент) для cost-exporter:

apiVersion: apps/v1kind: Deploymentmetadata:  name: cost-exporterspec:  selector:    matchLabels:      app: cost-exporter  template:    metadata:      labels:        app: cost-exporter    spec:      containers:      - name: cost-exporter        image: nachomillangarcia/prometheus_aws_cost_exporter:latest        args:        - --host        - 0.0.0.0        env:        - name: AWS_ACCESS_KEY_ID          value: "{{ .Values.aws_access_key_id }}"        - name: AWS_SECRET_ACCESS_KEY          value: "{{ .Values.aws_secret_access_key }}"        - name: METRIC_TODAY_DAILY_COSTS          value: "{{ .Values.env.metric_today_daily_costs }}"        - name: METRIC_YESTERDAY_DAILY_COSTS          value: "{{ .Values.env.metric_yesterday_daily_costs }}"        - name: QUERY_PERIOD          value: "{{ .Values.env.query_period }}"        - name: METRIC_TODAY_DAILY_USAGE          value: "{{ .Values.env.metric_today_daily_usage }}"        - name: METRIC_TODAY_DAILY_USAGE_NORM          value: "{{ .Values.env.metric_today_daily_usage_norm }}"

4. Настраиваем метрики для мониторинга

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

Здесь есть пример конфигурационного файла для cloudwatch_exporter с перечислением необходимых для мониторинга метрик.Посмотреть все доступные для мониторинга метрики например, для EC2 можно с помощью консольной утилиты aws:

aws cloudwatch list-metrics --namespace EC2

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

  - aws_namespace: AWS/NetworkELB    aws_metric_name: HealthyHostCount    aws_dimensions:    - LoadBalancer    - TargetGroup    aws_statistics:    - Sum    period_seconds: 60

Этот фрагмент указывает экспортеру брать из AWS/NetworkELB метрику HealthyHostCount с периодичностью 60 секунд, агрегировать её по LoadBalancer и TargetGroup, выдавать значение Sum.

Бонус! Несколько примеров алертов

Вот так выглядит алерт на использование CPU в Redis у ElastiCache:

  - alert: RedisCPUUsage    annotations:    description: |      Redis CPU utilization on {{`{{$labels.cache_cluster_id}}`}} in cluster is over than 60%    summary: Redis CPU utilization on {{`{{$labels.cache_cluster_id}}`}} in cluster is over than 60%    expr: |      aws_elasticache_cpuutilization_average >= 60    for: 5m

Алерт на количество target у LoadBalancer:

  - alert: LBTargetGroupIsUnhealthy    annotations:    description: Some hosts are target group {{`{{$labels.target_group}}`}} in cluster is unhealthy!    summary: Some hosts are target group {{`{{$labels.target_group}}`}} in cluster is unhealthy!    expr: |      aws_networkelb_healthy_host_count_sum{load_balancer=~".*someservice.*",target_group=~".*someservice.*"} < 3    for: 1m

Алерт на исчерпание EBS Burst balance:

  - alert: EBSBurst_balance    annotations:         description: EBS Burst balance in cluster is less than 60%                     summary: EBS Burst balance in cluster is less than 60%    expr: |      aws_ebs_burst_balance_average <= 60             for: 5m

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

Примеры, как могут выглядеть графики в Prometheus:

AWS EC2 EBS IO balance (average)AWS EC2 EBS IO balance (average)AWS ElastiCache CPU utilization (average)AWS ElastiCache CPU utilization (average)

Заключение

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

За рамками материала остались некоторые вопросы взаимодействия с Prometheus (как ему сообщать, откуда и куда scrapeить метрики), а также создание панелей в Grafana. (Кстати, для prometheus_aws_cost_exporter есть dashboard от создателя.) Разобравшись и с ними для своего конкретного случая, можно получить более полное, законченное решение.

P.S.

Читайте также в нашем блоге:

Подробнее..

Как готовить Helm правильно несколько полезных рецептов

16.05.2021 18:12:28 | Автор: admin
(источник фото -https://unsplash.com/photos/XWNbUhUINB8(источник фото -https://unsplash.com/photos/XWNbUhUINB8

Когда-то давно, когда ножей не знали,х@#$ говядину рубили... ой нет, это другая сказка, простите. Вот, правильная эта. Когда-то давно, деды сказывают, для обновления сервиса в среде инженерам приходилось самим писать скрипты для деплоймента, а некоторые даже запускали их сами из консоли, руками. Были даже причудливые инструменты вроде ClusterSSH, чтобы делать сеанс одновременной игры на всех нодах кластера.

Но тотальная контейнеризация, ввод в обиход универсального понятия "workload", и оркестризация привели к появлению Kubernetes, на котором сейчас работает примерно 3/4 мировых production сред.

Kubernetes ввёл в обиход концепцию управления конфигурацией при помощи дескрипторов - kubectl apply что в переводе означает "я не хочу объяснять что делать, я говорю как хочу чтобы в среде всё стало - а ты делай что должен, блестящий металлический зад!".

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

Поэтому Helm стал де-факто стандартом в автоматизированных деплойментах Kubernetes, добавляя новые интересные возможности, которые идут гораздо дальше простой альтернативы выполнению kubectl apply -f ...

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

Итак, напомним, что Helm в принципе может делать три основные вещи:

  • сделать дескрипторы по шаблонам

  • накатить дескрипторы на кластер

  • использовать репозитории charts - взять шаблоны дескрипторов из центральной среды

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

Шаблонизатор Helm работает примерно так:

Другими словами, Helm берёт исходники:

  • файлы, текстовые и бинарные

  • шаблоны .yaml

  • значения из одного или нескольких .yaml файлов, и, возможно, командной строки

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

При этом файлы вставляются в Secrets и ConfigMaps, а значения занимают свои места в шаблонах.

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

Рассмотрим некоторые полезные техники Helm для решения типичных задач, с которыми девопс инженер сталкивается за пределами простого, понятного, нежно-розового мира hello world:

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

  • использование секретов

  • повышение стабильности пайплайнов

Конфигурация множества сред

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

Другие тестовые среды предназначены, например, для приёмочного тестирования реальными пользователями (по уровню ответственности не Production - но весьма похожие). Такие среды обычно используются несколькими командами, поэтому все ожидают от них стабильности.

Production-среды имеют общие моменты, характерные для production, например реальный секретный ключ для платёжной системы. Но, тем не менее, могут различаться в других аспектах: например по региону, среда для "канареечных" релизов для тестов на малой группе, или по регионам. Или же может быть несколько production сред для каждого клиента или их группы, если ваш сервис больше похож на SaaS.

12 заповедей

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

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

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

Код с конфигурацией - как мясное с молочным? Код с конфигурацией - как мясное с молочным?

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

Каждый новый билд порождает неизменяемые (immutable) контейнер(ы) с кодом, и Helm chart, который можно применить для любой среды - от локального docker-desktop до production кластера в AWS.

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

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

Следовательно:

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

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

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

    • каждое значение конфигурации и/или файл должны храниться в одном и только в одном месте,

    • если значения или файлы различаются в зависимости от среды, в каждой среде сохраняются только отличающиеся части,

    • добавление файла в конфигурацию должно требовать именно этого - добавление файла: никаких изменений в пицот других yaml-ов!

Мы будем хранить конфигурации всех наших сред в диаграмме Helm как часть chart.

Пример ниже, дополнительные каталоги выделены (+).

/env             // (+) значения для сред /<chart-name>    // chart    /files         // (+) конфигурационные файлы и их шаблоны     /templates     // шаблоны Helm   Chart.yaml     // заглавный файл chart  values.yaml    // значения по умолчанию

Файлы со значениями для сред

Давайте посмотрим подробнее на структуру ваших сред.

Допустим у вас есть два типа, TEST и PROD для тестовых и продакшен сред, соответственно. тип TEST делится на две разновидности -STABLE и -PR (пул реквест, нестабильная среда), а для типа PROD у вас разновидности это регионы, EU и US.

Получается примерно такая структура для /env (значения для сред) и /files (файлы конфигурации):

/env                  TEST.yaml            // общие значения для всех тестовых сред  TEST-PR.yaml         // только для PR/нестабильной  TEST-STABLE.yaml     // только для стабильной     PROD.yaml            // общие значения для всех продакшен сред  PROD-EU.yaml         // продакшен EU     PROD-US.yaml         // продакшен US /files                     /TEST                // общие файлы для всех тестовых сред  /TEST-PR             // ...  /TEST-STABLE         // ...    /PROD                // общие файоы для всех продакшен сред   /PROD-EU             // ...  /PROD-US             // ...  /shared              // файлы общие для всех средvalues.yaml             // значения общие для всех сред

Теперь посмотрим что внутри /files - текстовые и бинарные файлы конфигурации.

.../PROD    /binary    /text/PROD-EU    /binary    /text .../shared    /binary    /text    /secret-text

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

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

1. Мы предполагаем что секретные файлы только текстовые а не бинарные. Почему? Потому что так проще. Секретный двоичный файл (например .p12 сертификат) становится несекретным, если зашифровать его секретным ключом с достаточной (скажем 120+ бит) энтропией - и можно хранить его просто в гите, даже если он размеров в несколько (десятков) килобайт. С точки зрения безопасности - это просто рандомный набор битов. А вот ключ, отпирающий этот бинарник, мы будем хранить в строгом секрете - как и все другие-остальные пароли.

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

Итак, когда структура выше подготовлена, всё работает примерно так - значения из нескольких файлов сначала превращаются в один плоский yaml, накладываясь друг на друга, в порядке уменьшающегося приоритета:

  • среда - разновидность (TEST-STABLE.yaml)

  • среда - тип (TEST.yaml)

  • общие значения (values.yaml)

Helm позволяет это сделать, указав файлы со значениями как последовательность опций --values:

helm upgrade --install <chart> path/to/<chart> --strict \     --values env/<env>.yaml --values env/<env>-<flavour>.yaml

В .yaml-файлах разновидности и типа среды содержатся атрибуты, например TEST-STABLE.yaml среди прочего содержит:

envFlavour: STABLE

а TEST.yaml содержит

envClass: TEST

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

Один ConfigMap и один Secret для всех файлов

Смотрим внимательно - вот одна, единая конфигурация для одного единственного ConfigMap и одного Secret, куда поместятся все ваши файлы. Бинарные файлы и текстовые несекретные файлы пойдут в ConfigMap, а секретные текстовые файлы в Secret.

# это нужно для вложенных range{{- $self := . -}} # список директорий, откуда берутся файлы - среда-разновидность, среда-тип и потом общие файлы из shared{{ $sources := (list "shared" .Values.envClass (printf "%s-%s" .Values.envFlavour .Values.envClass ) }}apiVersion: v1kind: ConfigMapmetadata:  name: myapp# вставить несекретные текстовые файлы как шаблоныdata:{{ range $env := $sources }}{{ range $path, $bytes := $self.Files.Glob (printf "files/%s/text/*" $env) }}  {{ base $path }}: {{ tpl ($self.Files.Get $path) $ | quote }}{{ end }}{{ end }}# вставить двоичные файлыbinaryData:{{ range $env := $sources }}{{ range $path, $bytes := $self.Files.Glob (printf "files/%s/binary/*" $env) }}  {{ base $path }}: {{ $self.Files.Get $path | b64enc | quote }}{{ end }}{{ end }}---apiVersion: v1kind: Secretmetadata:  name: myapp  labels:type: Opaquedata:# вставить секретные текстовые файлы как шаблоны{{ range $env := $sources }}{{ range $path, $bytes := $self.Files.Glob (printf "files/%s/secret-text/*" $env) }}  {{ base $path }}: {{ tpl ($self.Files.Get $path) $ | b64enc | quote }}{{ end }}{{ end }}

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

Тотальная шаблонизация

Имеющие опыт с Helm, возможно, задаются вопросом, к чему все эти хитрые танцы, если у Helm уже есть набор функций для ConfigMaps и Secrets?

А вот почему. Заметили маленькую функцию tpl, применяемую на каждый файл? Правильно, именно поэтому она нужна, чтобы каждый текстовый файл обрабатывался как отдельный шаблон - вы можете вставлять ссылки на значения как {{ .Values.myValue }}в любое место ваших текстовых файлов конфигурации.

Шаблон может использоваться для любого типа конфигурации, .properties, yaml, HOCON, например:

akka {  persistence {    cassandra {        keyspace = {{ .Values.cassandra.keyspace | quote }}        table = "{{ .Values.cassandra.tablePrefix }}messages"

Коварные кавычки

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

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

databasePassword: {{ .Values.databasePassword | quote }}

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

param/username={{ .Values.username | trimAll "\"" }}

Проецируемые тома (projected volumes)

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

Для этого в Kubernetes удачно завезли projected volumes - проецируемые тома, которые можно собирать из нескольких ConfigMaps и Secrets.

volumes:  - name: properties    projected:      defaultMode: 0640      sources:        - configMap:            name: myapp        - secret:            name: myapp

Очень просто смонтировать такой "сборный" том в директорию/confвашего приложения.

Линтер

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

У Helm есть для этого команды lint и template:

helm lint --debug path/to/<chart> --strict --values env/<env>.yaml \  --values env/<env>-<flavour>.yaml  helm template <chart> path/to/<chart> --strict --values env/<env>.yaml \  --values env/<env>-<flavour>.yaml

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

Но совершенству нет пределов (почти) - можно пойти ещё на шаг дальше и использовать yamllint для валидации yaml-дескрипторов. Это позволит отловить проблемы, которые иначе не получается ловить - например два файла с одним и тем же именем, которые оказались в PROD и PROD-EU, будут дважды вставлены в ConfigMap, что приведёт к ошибке при деплойменте.

Управление секретами

Теперь немного про то, как обращаться с секретами - например ключами платных API, паролями для баз данных и паролями от TLS-сертификатов, которые мы не хотим показывать никому, кроме самого сервиса.

Обычно секретные значения хранятся в отдельном сервисе, типа Heroku Vault, Azure Vault, Google Cloud KMS и подобных. В Helm даже есть плагин для управления секретами,но в большинстве компаний управление секретами централизовано, и инженерам не позволено, да и не нужно, трогать секреты из production.

Когда пайплайн запускает обновление сервиса в подобной среде, то сам пайплайн имеет возможность считать секреты и вставить их в конфигурационные файлы. В большинстве случаев (Gitlab, Circle, Azure, ...) секреты становятся переменными среды, и всё что требуется - это вставить их в шаблон в самом начале.

Для этого мы добавим секцию в values.yaml

# secretsdatabase_username: "${UserNameSecret}"database_password: "${DatabasePasswordSecret}"

И в нашем пайплайне испольуемenvsubstили нечто похожее:

cat <chart>/values.yaml | envsubst > <chart>/values-injected.yamlmv <chart>/values-injected.yaml <chart>/values.yaml

Такой подход позволяет ссылаться на секреты просто как {{ .Value.xxx }} в любом шаблоне, вставляя их туда куда им положено быть.

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

Чтобы решить этот вопрос, можно ввести конвенцию называть секреты как XXXSecret, и добавить что-то типа такого:

EXPOSED_SECRETS=$(grep Secret <chart>/files | grep -v secret-files | wc -l)if [ $EXPOSED_SECRETS -gt 0 ]; then fail "Secrets are exposed"; fi

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

Атомарные обновления сред

Теперь последний раздел - как использовать Helm hooks для того, чтобы повысить надёжность ваших пайплайнов.

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

Это может показаться сложным - особенно если вы хотите реализовать это самостоятельно, вооружившись простым kubectl apply -f ... Но, к счастью, Helm многое делает "прямо из коробки".

Флаг --atomic

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

helm upgrade --install my-chart some/path/to/my-chart \    --atomic --debug --timeout 300s

Helm откатит обновление, если проверки проб health/readiness не дали положительного результата в указанный срок. Хорошо, но можно лучше.

Hooks

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

И разумеется, сигнализировать Helm откатить обновление, если тест не прошёл.

apiVersion: batch/v1kind: Jobmetadata:  name: myapp  labels:  annotations:     "helm.sh/hook": post-install,post-upgrade     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeededspec:  template:    metadata:      name: myapp-smoke-test    spec:      restartPolicy: Never      containers:        - name: tests          image: test-image:           command: ['/bin/sh',                    '-c',                    '/test/run-test.sh']

Если вы используете--atomicфлаг и post-upgrade/post-install hook для тестов в пайплайне, вы можете со значительной долей уверенности считать пайплайн надёжным. Он будет иметь "зелёный" статус тогда, и только тогда, когда сервис был успешно обновлён, запущен и прошёл базовые тесты.

А если что-то пошло не так - Helm возвратит среду в то состояние, которое было до этого обновление, включая все конфигурации и дескрипторы.

Автоматически!

Заключение

Helm это бесплатный инструмент с открытым кодом для управления обновлениями сервисов и их конфигураций в кластерах Kubernetes.

Используя шаблоны и hooks, можно добиться того, что ваш continuous delivery плавен и надёжен настолько, что его практически никто не замечает.

***

Этот текст является авторским переводом, оригинал статьи этого же автора
https://jacum.medium.com/advanced-helm-practices-for-perfect-kubernetes-deployments-7fc4e00cc41c

Подробно об авторе - https://www.linkedin.com/in/tim-evdokimov/

Подробнее..

Перевод Оптимизируем затраты с помощью AWS Cost Explorer

15.04.2021 14:13:15 | Автор: admin

У Amazon Web Services отличный бесплатный пакет:хороший набор сервисов и щедрая раздача кредитов для разработчиков. Я был уверен: проблем с оплатой моего окружения не будет, поэтому о расходах не беспокоился. Мое приложение на 100% serverless, и я всегда укладывался в уровень бесплатного использования, так что просто игнорировал вопрос оплаты. В какой-то момент я расслабился и потерял бдительность.

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

AWS Cost Explorer

Сервис AWS Billing dashboard хорошо подходит для оплаты счетов и показывает график прогноза счетов за текущий месяц. Но этот сервис едва ли претендует на звание лучшего в AWS. Месячный прогноз часто врет, поэтому лучше игнорировать его вовсе.

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

Используя Cost Explorer, я смог заранее определить уязвимые места и исправить их задолго до того, как с меня начнут списывать за них деньги. Еще раз спасибо AWS.

Пользовательский интерфейс

Прежде чем начать работать, надо познакомиться со стандартным видом консоли Billing Dashboard. Нужно сначала включить её, что будет стоить денег. Лучше сделать это заранее, чтобы потом не было мучительно больно. У кого много остатку, тот не боится недостатку!

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

Это мой график потраченного за последние несколько месяцев.

Отчеты

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

Бюджеты

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

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

Обнаружение аномалий

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

Cost Explorer API

Стандартный вид консоли управления меня устраивает но только для эпизодического ознакомления. Для того, чтобы получить нечто большее, AWS предоставляет отличный API. Репозиторий AWS Samples Github дает нам наглядный пример доступа к API Cost Explorer.

Мой код основан на этом примере, и позволяет разработать собственный отчет для Cost Explorera.

Код Lambda функции

import osimport sys# Required to load modules from vendored subfolder (for clean development env)sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "./vendored"))import boto3import datetimeimport loggingimport pandas as pd#For datefrom dateutil.relativedelta import relativedelta#For emailfrom email.mime.application import MIMEApplicationfrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMETextfrom email.utils import COMMASPACE, formatdateSES_REGION="ap-south-1"CURRENT_MONTH = True#Default exclude support, as for Enterprise Support#as support billing is finalised later in month so skews trends    INC_SUPPORT = os.environ.get('INC_SUPPORT')if INC_SUPPORT == "true":    INC_SUPPORT = Trueelse:    INC_SUPPORT = FalseTAG_VALUE_FILTER = os.environ.get('TAG_VALUE_FILTER') or '*'TAG_KEY = os.environ.get('TAG_KEY')class CostExplorer:    """Retrieves BillingInfo checks from CostExplorer API    >>> costexplorer = CostExplorer()    >>> costexplorer.addReport(GroupBy=[{"Type": "DIMENSION","Key": "SERVICE"}])    >>> costexplorer.generateExcel()    """        def __init__(self, CurrentMonth=False):        #Array of reports ready to be output to Excel.        self.reports = []        self.client = boto3.client('ce', region_name='us-east-1')        # self.end = datetime.date.today().replace(day=1)        self.riend = datetime.date.today()        self.end = self.riend        # Default is last 12 months        self.start = (datetime.date.today() - relativedelta(months=+12)).replace(day=1) #1st day of month 12 months ago        self.ristart = (datetime.date.today() - relativedelta(months=+11)).replace(day=1) #1st day of month 11 months ago        self.sixmonth = (datetime.date.today() - relativedelta(months=+6)).replace(day=1) #1st day of month 6 months ago, so RI util has savings values        self.accounts = {}    def addRiReport(self, Name='RICoverage', Savings=False, PaymentOption='PARTIAL_UPFRONT', Service='Amazon Elastic Compute Cloud - Compute'): #Call with Savings True to get Utilization report in dollar savings        type = 'chart' #other option table        if Name == "RICoverage":            results = []            response = self.client.get_reservation_coverage(                TimePeriod={                    'Start': self.ristart.isoformat(),                    'End': self.riend.isoformat()                },                Granularity='MONTHLY'            )            results.extend(response['CoveragesByTime'])            while 'nextToken' in response:                nextToken = response['nextToken']                response = self.client.get_reservation_coverage(                    TimePeriod={                        'Start': self.ristart.isoformat(),                        'End': self.riend.isoformat()                    },                    Granularity='MONTHLY',                    NextPageToken=nextToken                )                results.extend(response['CoveragesByTime'])                if 'nextToken' in response:                    nextToken = response['nextToken']                else:                    nextToken = False            rows = []            for v in results:                row = {'date':v['TimePeriod']['Start']}                row.update({'Coverage%':float(v['Total']['CoverageHours']['CoverageHoursPercentage'])})                rows.append(row)              df = pd.DataFrame(rows)            df.set_index("date", inplace= True)            df = df.fillna(0.0)            df = df.T        elif Name in ['RIUtilization','RIUtilizationSavings']:            #Only Six month to support savings            results = []            response = self.client.get_reservation_utilization(                TimePeriod={                    'Start': self.sixmonth.isoformat(),                    'End': self.riend.isoformat()                },                Granularity='MONTHLY'            )            results.extend(response['UtilizationsByTime'])            while 'nextToken' in response:                nextToken = response['nextToken']                response = self.client.get_reservation_utilization(                    TimePeriod={                        'Start': self.sixmonth.isoformat(),                        'End': self.riend.isoformat()                    },                    Granularity='MONTHLY',                    NextPageToken=nextToken                )                results.extend(response['UtilizationsByTime'])                if 'nextToken' in response:                    nextToken = response['nextToken']                else:                    nextToken = False            rows = []            if results:                for v in results:                    row = {'date':v['TimePeriod']['Start']}                    if Savings:                        row.update({'Savings$':float(v['Total']['NetRISavings'])})                    else:                        row.update({'Utilization%':float(v['Total']['UtilizationPercentage'])})                    rows.append(row)                  df = pd.DataFrame(rows)                df.set_index("date", inplace= True)                df = df.fillna(0.0)                df = df.T                type = 'chart'            else:                df = pd.DataFrame(rows)                type = 'table' #Dont try chart empty result        elif Name == 'RIRecommendation':            results = []            response = self.client.get_reservation_purchase_recommendation(                #AccountId='string', May use for Linked view                LookbackPeriodInDays='SIXTY_DAYS',                TermInYears='ONE_YEAR',                PaymentOption=PaymentOption,                Service=Service            )            results.extend(response['Recommendations'])            while 'nextToken' in response:                nextToken = response['nextToken']                response = self.client.get_reservation_purchase_recommendation(                    #AccountId='string', May use for Linked view                    LookbackPeriodInDays='SIXTY_DAYS',                    TermInYears='ONE_YEAR',                    PaymentOption=PaymentOption,                    Service=Service,                    NextPageToken=nextToken                )                results.extend(response['Recommendations'])                if 'nextToken' in response:                    nextToken = response['nextToken']                else:                    nextToken = False            rows = []            for i in results:                for v in i['RecommendationDetails']:                    row = v['InstanceDetails'][list(v['InstanceDetails'].keys())[0]]                    row['Recommended']=v['RecommendedNumberOfInstancesToPurchase']                    row['Minimum']=v['MinimumNumberOfInstancesUsedPerHour']                    row['Maximum']=v['MaximumNumberOfInstancesUsedPerHour']                    row['Savings']=v['EstimatedMonthlySavingsAmount']                    row['OnDemand']=v['EstimatedMonthlyOnDemandCost']                    row['BreakEvenIn']=v['EstimatedBreakEvenInMonths']                    row['UpfrontCost']=v['UpfrontCost']                    row['MonthlyCost']=v['RecurringStandardMonthlyCost']                    rows.append(row)              df = pd.DataFrame(rows)            df = df.fillna(0.0)            type = 'table' #Dont try chart this        self.reports.append({'Name':Name,'Data':df, 'Type':type})    def addReport(self, Name="Default",GroupBy=[{"Type": "DIMENSION","Key": "SERVICE"},],     Style='Total', NoCredits=True, CreditsOnly=False, RefundOnly=False, UpfrontOnly=False, IncSupport=False):        type = 'chart' #other option table        results = []        if not NoCredits:            response = self.client.get_cost_and_usage(                TimePeriod={                    'Start': self.start.isoformat(),                    'End': self.end.isoformat()                },                Granularity='MONTHLY',                Metrics=[                    'UnblendedCost',                ],                GroupBy=GroupBy            )        else:            Filter = {"And": []}            Dimensions={"Not": {"Dimensions": {"Key": "RECORD_TYPE","Values": ["Credit", "Refund", "Upfront", "Support"]}}}            if INC_SUPPORT or IncSupport: #If global set for including support, we dont exclude it                Dimensions={"Not": {"Dimensions": {"Key": "RECORD_TYPE","Values": ["Credit", "Refund", "Upfront"]}}}            if CreditsOnly:                Dimensions={"Dimensions": {"Key": "RECORD_TYPE","Values": ["Credit",]}}            if RefundOnly:                Dimensions={"Dimensions": {"Key": "RECORD_TYPE","Values": ["Refund",]}}            if UpfrontOnly:                Dimensions={"Dimensions": {"Key": "RECORD_TYPE","Values": ["Upfront",]}}            tagValues = None            if TAG_KEY:                tagValues = self.client.get_tags(                    SearchString=TAG_VALUE_FILTER,                    TimePeriod = {                        'Start': self.start.isoformat(),                        'End': datetime.date.today().isoformat()                    },                    TagKey=TAG_KEY                )            if tagValues:                Filter["And"].append(Dimensions)                if len(tagValues["Tags"]) > 0:                    Tags = {"Tags": {"Key": TAG_KEY, "Values": tagValues["Tags"]}}                    Filter["And"].append(Tags)            else:                Filter = Dimensions.copy()            response = self.client.get_cost_and_usage(                TimePeriod={                    'Start': self.start.isoformat(),                    'End': self.end.isoformat()                },                Granularity='MONTHLY',                Metrics=[                    'UnblendedCost',                ],                GroupBy=GroupBy,                Filter=Filter            )        if response:            results.extend(response['ResultsByTime'])            while 'nextToken' in response:                nextToken = response['nextToken']                response = self.client.get_cost_and_usage(                    TimePeriod={                        'Start': self.start.isoformat(),                        'End': self.end.isoformat()                    },                    Granularity='MONTHLY',                    Metrics=[                        'UnblendedCost',                    ],                    GroupBy=GroupBy,                    NextPageToken=nextToken                )                results.extend(response['ResultsByTime'])                if 'nextToken' in response:                    nextToken = response['nextToken']                else:                    nextToken = False        rows = []        sort = ''        for v in results:            row = {'date':v['TimePeriod']['Start']}            sort = v['TimePeriod']['Start']            for i in v['Groups']:                key = i['Keys'][0]                if key in self.accounts:                    key = self.accounts[key][ACCOUNT_LABEL]                row.update({key:float(i['Metrics']['UnblendedCost']['Amount'])})             if not v['Groups']:                row.update({'Total':float(v['Total']['UnblendedCost']['Amount'])})            rows.append(row)          df = pd.DataFrame(rows)        df.set_index("date", inplace= True)        df = df.fillna(0.0)        if Style == 'Change':            dfc = df.copy()            lastindex = None            for index, row in df.iterrows():                if lastindex:                    for i in row.index:                        try:                            df.at[index,i] = dfc.at[index,i] - dfc.at[lastindex,i]                        except:                            logging.exception("Error")                            df.at[index,i] = 0                lastindex = index        df = df.T        df = df.sort_values(sort, ascending=False)        self.reports.append({'Name':Name,'Data':df, 'Type':type})    def generateExcel(self):        # Create a Pandas Excel writer using XlsxWriter as the engine.\        os.chdir('/tmp')        writer = pd.ExcelWriter('cost_explorer_report.xlsx', engine='xlsxwriter')        workbook = writer.book        for report in self.reports:            print(report['Name'],report['Type'])            report['Data'].to_excel(writer, sheet_name=report['Name'])            worksheet = writer.sheets[report['Name']]            if report['Type'] == 'chart':                # Create a chart object.                chart = workbook.add_chart({'type': 'column', 'subtype': 'stacked'})                chartend=13                for row_num in range(1, len(report['Data']) + 1):                    chart.add_series({                        'name':       [report['Name'], row_num, 0],                        'categories': [report['Name'], 0, 1, 0, chartend],                        'values':     [report['Name'], row_num, 1, row_num, chartend],                    })                chart.set_y_axis({'label_position': 'low'})                chart.set_x_axis({'label_position': 'low'})                worksheet.insert_chart('O2', chart, {'x_scale': 2.0, 'y_scale': 2.0})        writer.save()        #Time to deliver the file to S3        if os.environ.get('S3_BUCKET'):            s3 = boto3.client('s3')            s3.upload_file("cost_explorer_report.xlsx", os.environ.get('S3_BUCKET'), "cost_explorer_report.xlsx")        if os.environ.get('SES_SEND'):            #Email logic            msg = MIMEMultipart()            msg['From'] = os.environ.get('SES_FROM')            msg['To'] = COMMASPACE.join(os.environ.get('SES_SEND').split(","))            msg['Date'] = formatdate(localtime=True)            msg['Subject'] = "Cost Explorer Report"            text = "Find your Cost Explorer report attached\n\n"            msg.attach(MIMEText(text))            with open("cost_explorer_report.xlsx", "rb") as fil:                part = MIMEApplication(                    fil.read(),                    Name="cost_explorer_report.xlsx"                )            part['Content-Disposition'] = 'attachment; filename="%s"' % "cost_explorer_report.xlsx"            msg.attach(part)            #SES Sending            ses = boto3.client('ses', region_name=SES_REGION)            result = ses.send_raw_email(                Source=msg['From'],                Destinations=os.environ.get('SES_SEND').split(","),                RawMessage={'Data': msg.as_string()}            )     def lambda_handler(event, context):    costexplorer = CostExplorer(CurrentMonth=False)    #Default addReport has filter to remove Support / Credits / Refunds / UpfrontRI    #Overall Billing Reports    costexplorer.addReport(Name="Total", GroupBy=[],Style='Total',IncSupport=True)    costexplorer.addReport(Name="TotalChange", GroupBy=[],Style='Change')    costexplorer.addReport(Name="TotalInclCredits", GroupBy=[],Style='Total',NoCredits=False,IncSupport=True)    costexplorer.addReport(Name="TotalInclCreditsChange", GroupBy=[],Style='Change',NoCredits=False)    costexplorer.addReport(Name="Credits", GroupBy=[],Style='Total',CreditsOnly=True)    costexplorer.addReport(Name="Refunds", GroupBy=[],Style='Total',RefundOnly=True)    costexplorer.addReport(Name="RIUpfront", GroupBy=[],Style='Total',UpfrontOnly=True)    #GroupBy Reports    costexplorer.addReport(Name="Services", GroupBy=[{"Type": "DIMENSION","Key": "SERVICE"}],Style='Total',IncSupport=True)    costexplorer.addReport(Name="ServicesChange", GroupBy=[{"Type": "DIMENSION","Key": "SERVICE"}],Style='Change')    costexplorer.addReport(Name="Accounts", GroupBy=[{"Type": "DIMENSION","Key": "LINKED_ACCOUNT"}],Style='Total')    costexplorer.addReport(Name="AccountsChange", GroupBy=[{"Type": "DIMENSION","Key": "LINKED_ACCOUNT"}],Style='Change')    costexplorer.addReport(Name="Regions", GroupBy=[{"Type": "DIMENSION","Key": "REGION"}],Style='Total')    costexplorer.addReport(Name="RegionsChange", GroupBy=[{"Type": "DIMENSION","Key": "REGION"}],Style='Change')    if os.environ.get('COST_TAGS'): #Support for multiple/different Cost Allocation tags        for tagkey in os.environ.get('COST_TAGS').split(','):            tabname = tagkey.replace(":",".") #Remove special chars from Excel tabname            costexplorer.addReport(Name="{}".format(tabname)[:31], GroupBy=[{"Type": "TAG","Key": tagkey}],Style='Total')            costexplorer.addReport(Name="Change-{}".format(tabname)[:31], GroupBy=[{"Type": "TAG","Key": tagkey}],Style='Change')    #RI Reports    costexplorer.addRiReport(Name="RICoverage")    costexplorer.addRiReport(Name="RIUtilization")    costexplorer.addRiReport(Name="RIUtilizationSavings", Savings=True)    costexplorer.addRiReport(Name="RIRecommendation") #Service supported value(s): Amazon Elastic Compute Cloud - Compute, Amazon Relational Database Service    costexplorer.generateExcel()    return "Report Generated"

IAM Role

Чтобы запускаться, Lambda функция должна обладать ролью с приведенными ниже правами:

Базовая политика Lambda

{    "Version": "2012-10-17",    "Statement": [        {            "Effect": "Allow",            "Action": [                "logs:CreateLogGroup",                "logs:CreateLogStream",                "logs:PutLogEvents"            ],            "Resource": "*"        }    ]}

Разрешение для записи отчетов в S3 бакет

{    "Version": "2012-10-17",    "Statement": [        {            "Sid": "VisualEditor0",            "Effect": "Allow",            "Action": [                "s3:PutObject",                "s3:GetObject"            ],            "Resource": "arn:aws:s3:::account.admin/*"        }    ]}

Simple Email Service

{    "Version": "2012-10-17",    "Statement": [        {            "Sid": "VisualEditor0",            "Effect": "Allow",            "Action": [                "ses:SendEmail",                "ses:SendRawEmail"            ],            "Resource": "*"        }    ]}

Cost Explorer

{    "Version": "2012-10-17",    "Statement": [        {            "Sid": "VisualEditor0",            "Effect": "Allow",            "Action": "ce:*",            "Resource": "*"        }    ]}

Запуск на Event Bridge

Наконец, мы настраиваем регулярный запуск нашей Lambda функции на Event Bridge, например, 5 числа каждого месяца. В результате работы всех настроек я буду получать email с прикрепленным XLS-отчетом. Также можно настраивать срабатывание еженедельно и даже на определенные дни недели, при необходимости.

Подробнее..

Бесплатные сервисы для разработчиков огромный список

06.04.2021 12:11:10 | Автор: admin

Бесплатное хранилище артефактов PackageCloud

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

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

Но для некоторых бесплатный тариф единственный способ завлечь новых клиентов. Это просто замечательно с точки зрения самих пользователей. Ведь перед нами десятки бесплатных хостингов, API, CMS, CDN, сервисов обработки данных, поисковых движков, репозиториев, инструментов проверки кода и других. Бесплатный тариф идеален для опенсорс-разработчиков, любительских и некоммерческих проектов, маленьких стартапов. Ни за что не надо платить.

Например, огромный список бесплатных сервисов для разработчиков ведётся в репозитории free-for-dev. Список составлен пул-реквестами более 900 участников.

Важно подчеркнуть, что конкретно в этом списке отсутствуют альтернативы на своём хостинге (о них см. ниже). Здесь исключительно онлайновые сервисы, то есть SaaS, PaaS, IaaS.

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

Для примера вот несколько тематических категорий.

Основные облачные провайдеры


Ниже указано, в каком объёме предоставляются бесплатные услуги.

Google Cloud Platform

  • App Engine 28 часов фронтенд-инстансов в день, 9 часов бэкенд-инстансов в день
  • Cloud Firestore 1ГБ места, 50000 чтений, 20000 записей, 20000 удалений в день
  • Compute Engine 1 невытесняемый инстанс f1-micro, 30ГБHDD, 5ГБ для снапшотов (не для всех регионов), сеть 1ГБ из Северной Америки во все регионы (кроме Китая и Аргентины) в месяц
  • Cloud Storage 5ГБ, трафик 1ГБ
  • Cloud Shell веб-терминал Linux и базовая IDE с хранилищем на 5ГБ. Лимит 60 часов в неделю
  • Cloud Pub/Sub 10ГБ сообщений в месяц
  • Cloud Functions 2 млн вызовов в месяц (включая все фоновые и HTTP-вызовы)
  • Cloud Run 2 млн запросов в месяц, 360000гигабайт-секунд памяти, 180000 vCPU-секунд вычислительного времени, трафик 1ГБ в месяц из Северной Америки в другие регионы
  • Google Kubernetes Engine отсутствие платы за управление для одного зонального кластера. Но при этом все узлы оплачиваются по стандартной цене Compute Engine
  • BigQuery 1ТБ запросов в месяц, 10ГБ хранилище на месяц
  • Cloud Build 120 минут сборки в день
  • Cloud Source Repositories до 5 пользователей, хранилище 50ГБ, трафик 50ГБ
  • Полный список бесплатных тарифов Google Cloud

Amazon Web Services

  • Amazon DynamoDB СУБД NoSQL на 25ГБ
  • Amazon Lambda 1млн запросов в месяц
  • Amazon SNS 1млн нотификаций в месяц
  • Amazon Cloudwatch 10 пользовательских метрик и 10 предупреждений
  • Amazon Glacier 10ГБ долговременного хранилища объектов
  • Amazon SQS 1 млн запросов из очереди сообщений
  • Amazon CodeBuild 100 минут сборки в месяц
  • Amazon Code Commit 5 активных пользователей в месяц
  • Amazon Code Pipeline 1 активный конвейер в месяц
  • Полный список бесплатных тарифов AWS

Microsoft Azure

  • Virtual Machines 1 виртуальная машина B1S под Linux, одна B1S под Windows
  • App Service 10 приложений (веб, мобильные или API)
  • Functions 1 млн запросов в месяц
  • DevTest Labs среда разработки и тестирования
  • Active Directory 500000 объектов
  • Active Directory B2C хранилище на 50000 пользователей в месяц
  • Azure DevOps 5 активных пользователей, неограниченные приватные репозитории Git
  • Azure Pipelines 10 бесплатных параллельных задач с неограниченным временем выполнения для опенсорсных проектов под Linux, macOS и Windows
  • Microsoft IoT Hub 8000 сообщений в день
  • Load Balancer 1 бесплатный публичный IP (VIP) с балансировкой нагрузки
  • Notification Hubs 1млн пуш-нотификаций
  • Bandwidth внешний трафик 5ГБ в месяц
  • Cosmos DB 5ГБ хранилище и обеспеченная пропускная способность на 400 RU (реквест-юнитов)
  • Static Web Apps сборка, деплой и хостинг статичных приложений и бессерверных функций, с бесплатным SSL, аутентификацией/авторизацией и пользовательскими доменами
  • Storage хранилище для файлов и блобов на 5ГБ в LRS (locally redundant storage)
  • Cognitive Services AI/ML API (компьютерное зрение, перевод, распознавание лиц, боты...) с бесплатным лимитом использования
  • Cognitive Search сервис индексации текстов и поиск на основе ИИ, бесплатно на 10000 документов
  • Azure Kubernetes Service бесплатное управление кластером Kubernetes (хотя при этом оплачиваются сами виртуальные машины, хранение данных и другие сервисы за пределами бесплатных лимитов)
  • Event Grid 100тыс. операций в месяц
  • Полный список бесплатных тарифов Azure

Oracle Cloud

  • Compute два инстанса VM.Standard.E2.1.Micro 1ГБ RAM
  • Block Volume 2 тома, в сумме 100ГБ (используется для вычислений)
  • Object Storage 10 ГБ
  • Load Balancer 1 инстанс на 10 Мбит/с
  • Databases 2 базы данных, по 20 ГБ каждая
  • Monitoring приём до 500млн точек данных, выдача до 1млрд точек данных
  • Bandwidth внешний трафик 10ТБ в месяц с ограничением скорости 5Мбит/с
  • Notifications 1 млн нотификаций в месяц, 1000 отправленных писем
  • Полный список бесплатных тарифов Oracle Cloud

IBM Cloud

  • Cloud Functions 5 млн выполнений в месяц
  • Object Storage 25ГБ в месяц
  • Cloudant Database хранилище на 1 ГБ
  • Db2 Database хранилище на 100МБ
  • API Connect 50000 вызовов API в месяц
  • Availability Monitoring 3 млн точек данных в месяц
  • Log Analysis анализ логов до 500МБ в сутки
  • Полный список бесплатных тарифов IBM Cloud

Аналитика, статистика, логи


Вот несколько сервисов бесплатной аналитики для мобильных приложений и сайтов. Здесь только бесплатные сторонние сервисы. Многие из них можно использовать вместо скриптов Google Analytics, поскольку GA рассматривается как угроза приватности.

Примечание. Программы self-hosted см. в отдельной категории.

  • AO Analytics бесплатная аналитика для любых сайтов, без ограничений по объёму
  • Indicative платформа аналитики до 50млн событий в месяц
  • Amplitude 1 млн событий в месяц, до 2 приложений
  • GoatCounter опенсорсная платформа веб-аналитики бесплатно для некоммерческого использования или self-hosted версия бесплатно для всех. Позиционируется как более приватная альтернатива коммерческим сервисам Google Analytics и Matomo. Бесплатный лимит 6 месяцев хранения данных и 100тыс. просмотров в месяц.
  • Google Analytics, без комментариев
  • Expensify учёт расходов, контроль личных финансов
  • GetInsights система аналитики без куков, бесплатно до 5000 событий в месяц.
  • Heap автоматический трекинг действий пользователя в iOS или веб-приложениях. Бесплатно до 5000 визитов в месяц
  • Keen разнообразные инструменты для сбора данных, анализа и визуализации. Бесплатно до 50000 событий в месяц
  • Яндекс.Метрика российская альтернатива GA, но не лишённая недостатков последнего (в том числе угроза приватности со стороны материнской корпорации)
  • Mixpanel лимит 100000 пользователей в месяц, неограниченный срок хранения данных


    Mixpanel
  • Moesif аналитика API для REST и GraphQL, бесплатно до 500000 вызовов API в месяц
  • Molasses Флаги функций и A/B-тестирование, бесплатно до 3 окружений по 5 флагов функций в каждом.
  • Optimizely A/B-тестирование, бесплатный стартовый план на 1 сайт, 1 приложение iOS и 1 приложение Android
  • Quantcast новый сервис бесплатной аналитики, запущен в марте 2021 года, лимиты бесплатного тарифа официально не объявлены
  • Sematext бесплатно до 50тыс. действий в месяц, хранение данных 1 день
  • Tableau Developer Program бесплатная версия для разработчиков (предрелизная тестовая версия аналитической платформы)
  • UsabilityHub тестирование юзабилити и эффективности разных вариантов веб-дизайна. Бесплатные тесты до 2 минут
  • Woopra бесплатная платформа аналитики для любых продуктов, до 500тыс. действий в месяц, хранение данных до 90 дней

Другие категории



Эмулятор основных операционных систем в браузере copy.sh

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


Опенсорсные инструменты безопасности


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

Например, в нём есть системы для управления уязвимостями Faraday, Archery Sec, Jackhammer,
Watchdog и OpenVAS, сканер контейнеров trivy, менеджеры конфигурация вроде MGMT, Chef и Puppet, бесплатные системы SIEM (анализ событий в реальном времени и реагирование), VPN, инструменты для улучшения безопасности систем на Linux и Windows (Bastille, JShielder, nixarmor, Zeus (AWS), Docker-bench и др.), защита аутентификации в Linux, чёрные списки IP и доменов, прокси, socks-серверы, HTTP-туннели, FTP-прокси, DNS-прокси, инструменты сетевого и серверного мониторинга, системы для определения вторжений в сеть и на хост (NIDS и HIDS, соответственно), мониторинг и анализ логов, антивирусы, спам-фильтры, симуляторы инфраструктуры, файрволы для веб-приложений, сетевые сканеры, системы форензики (поиск цифровых улик), программы анализа файлов, метаданных, оперативной памяти и многие другие инструменты.

Всё бесплатно и с открытыми исходниками.

Бесплатные альтернативы на своём хостинге


Вышеупомянутый список free-for-dev не включает бесплатные инструменты на своём хостинге. Однако их очень много. Обычно это опенсорсные программы. Бывает, что какой-то коммерческий сервис SaaS одновременно публикует исходники, то есть предлагает параллельно платный и бесплатный тариф.

Вот список бесплатных альтернатив на своём хостинге в 81 категории из коллекции awesome-selfhosted:



Списки бесплатных ресурсов для разработчиков также ведутся в проектах FOSS-for-Dev, getAwesomeness и De-google-ify Internet.

Надеемся, что эта подборка окажется кому-то полезной.



Наша компания предлагает облачные серверы для любых задач и на любой операционной системе. Создавайте собственные конфигурации в течение минуты, минимальный тариф всего 6.5 рублей в день!
Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Перевод Расширение кластера PostgreSQL размером 5,7ТБ и переход с версии 9.6 на 12.4

26.01.2021 16:05:52 | Автор: admin

Фото Ричарда Джекобса на Unsplash

В ноябре 2020 года мы начали крупную миграцию для обновления кластера PostgreSQL с версии 9.6 на 12.4. В этом посте я вкратце расскажу про нашу архитектуру в компании Coffee Meets Bagel, объясню, как даунтайм апгрейда удалось снизить ниже 30 минут, и расскажу про то, что мы узнали в процессе.

Архитектура


Для справки: Coffee Meets Bagel это приложение для романтических знакомств с системой курирования. Каждый день наши пользователи получают в полдень по их часовому поясу ограниченную партию высококачественных кандидатов. Это приводит к хорошо предсказуемым закономерностям нагрузки. Если посмотреть данные за последнюю неделю от момента написания статьи, у нас в среднем получается 30 тысяч транзакций в секунду, в пике до 65 тысяч.



До обновления у нас работали 6 серверов Postgres на инстансах i3.8xlarge в AWS. Они содержали одну главную ноду, три реплики для раздачи веб-трафика только для чтения, балансируемые с помощью HAProxy, один сервер для асинхронных воркеров и один сервер для ETL [Extract, Transform, Load] и Business Intelligence.

Для поддержания парка реплик в актуальном состоянии мы полагаемся на встроенную в Postgres потоковую репликацию.



Причины для апгрейда


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


Мой кандидат для подреддита r/uptimeporn

Как итог, накопилось множество странностей, которые заставляют понервничать. К примеру, новые сервисы в systemd не запускаются. Пришлось настраивать запуск агента datadog в сессии screen. Иногда SSH переставал отвечать при загрузке процессора выше50%, а сам сервер исправно отдавал запросы базы данных.

А ещё свободное место на диске начало подходить к опасным значениям. Как я упоминал выше, Postgres работал на инстансах i3.8xlarge в EC2, у которых 7,6ТБ хранилища NVMe. В отличие от EBS, здесь размер диска динамически менять нельзя что заложено изначально, то и будет. И мы заполнили примерно 75% диска. Стало понятно, что для поддержания будущего роста размер инстанса придётся менять.

Наши требования


  1. Минимальный даунтайм. Мы поставили целью ограничение в 4 часа суммарного даунтайма, включая незапланированные отключения, вызванные ошибками при обновлении.
  2. Собрать новый кластер баз данных на новых инстансах для замены текущего парка стареющих серверов.
  3. Перейти на i3.16xlarge, чтобы был простор для роста.

Нам известны три способа выполнить обновление Postgres: создание резервной копии и восстановление из неё, pg_upgrade и логическая репликация pglogical.

От первого способа, восстановления из резервной копии, мы отказались сразу: для нашего датасета на 5,7ТБ он занял бы слишком много времени. При своей скорости приложение pg_upgrade не удовлетворяло требованиям 2 и 3: это инструмент для миграции на той же машине. Поэтому мы выбрали логическую репликацию.

Наш процесс


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


Мы создали новый primary-сервер Postgres 12 и с помощью pglogical синхронизировали все наши данные. Когда он синхронизировался и перешёл к репликации входящих изменений, мы начали добавлять за него потоковые реплики. После настройки новой потоковой реплики мы включали её в HAProxy, а одну из старых версии 9.6 удаляли.

Этот процесс продолжался до полного отключения серверов Postgres 9.6, кроме мастера. Конфигурация приняла следующий вид.



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

  1. Перевод сайта в режим технических работ;
  2. Смена записей DNS мастера на новый сервер;
  3. Принудительная синхронизация всех последовательностей (sequences) первичных ключей (primary key);
  4. Ручной запуск контрольной точки (CHECKPOINT) на старом мастере.
  5. На новом мастере выполнение некоторых процедур валидации данных и тестов;
  6. Включение сайта.

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

Извлечённые уроки


При общем успехе операции пара проблем по пути всё же встретилась. Самая страшная из них чуть не убила наш мастер Postgres 9.6

Урок 1: медленная синхронизация может быть опасной


Обозначим для начала контекст: как работает pglogical? Процесс передачи (sender) на поставщике (provider, в данном случае наш старый мастер 9.6) декодирует упреждающий журнал WAL [write-ahead log], извлекает логические изменения и посылает их на подписчика (subscriber).

Если подписчик отстаёт, то поставщик будет хранить сегменты WAL, чтобы когда подписчик его нагонит, никаких данных не потерялось.

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

На практике это означает, что при синхронизации большой таблицы на системе с большой нагрузкой по записям/изменениям нужно тщательно следить за использованием диска. При первой попытке синхронизации нашей самой крупной (4ТБ) таблицы команда с оператором COPY работала больше суток. За это время на ноде поставщика набралось больше одного терабайта упреждающих журналов WAL.

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


Доступное дисковое пространство на старом мастере при первой попытке синхронизации

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

  • Удалили все индексы в синхронизируемой таблице;
  • fsynch переключили на off;
  • Поменяли max_wal_size на 50GB;
  • Поменяли checkpoint_timeout на 1h.

Эти четыре действия значительно ускорили процесс синхронизации на подписчике, и наша вторая попытка синхронизации таблицы завершилась за 8 часов.

Урок 2: каждое изменение строк журналируется как конфликт


Когда pglogical обнаруживает конфликт, приложение оставляет в логах запись вида CONFLICT: remote UPDATE on relation PUBLIC.foo. Resolution: apply_remote.

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

Эту проблему удалось решить заданием параметра pglogical.conflict_log_level = DEBUG в файле postgresql.conf.

Об авторе


Томми Ли старший инженер программного обеспечения в компании Coffee Meets Bagel. До этого он работал в Microsoft и канадском производителе систем автоматизирования бухгалтерского учёта Wave HQ.
Подробнее..

Сам себе DevOps строим cloud-only CI для веб приложения

22.05.2021 18:12:52 | Автор: admin

Привет, Хабр! Сегодня мы немного поговорим о DevOps и самоорганизации на примере одного из наших проектов.

Начнем с фразы, с которой не соглашается добрая половина разработчиков в индустрии: "каждый разработчик должен быть сам себе DevOps". Кто-то считает, что этим должен заниматься отдельно выделенный человек, чтобы у разработчика оставалась забота только о качестве кода. А кому-то свойственно думать о конвейере доставки кода в той же степени, как и о самом коде. Я же считаю, что в современных реалиях рынка и избытке инструментов/знаний разработчик должен уметь настроить и обслуживать конвейер быстрой и предсказуемой доставки артефакта в нужную ему среду. В отличие от мобильных разработчиков, для которых вопросы инфраструктуры и доставки приложения в большей степени решены самим вендором (Google и Apple), backend и web разработчики должны если не владеть, то хотя бы интересоваться практиками доставки кода.

И речь не идет о настройке каких-то больших и громоздких билд-систем, для которых обычно приносится в жертвую целая штатная единица. Нет. DevOps - не человек, а система ежедневных маленьких привычек, основанных на самоорганизации. Понятие, взрастающее снизу вверх, а не сверху или в бок. И если вы, как разработчик, смогли ускорить поток артефактов (любимое американцами понятие "Value Stream") на небольшой процент, то поздравляем - это уже DevOps way. Рекомендуем прочесть книгу "DevOps Handbook" by Gene Kim - лучшая книга для понимания этого концепта (ссылка в конце статьи).

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

Кто

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

  • 3 фронтенд разработчика с кучей пулл реквестов в день

  • 2 тестировщика, бастующие за улучшение QX (QA experience)

Что

Клиентское и администраторское web-приложения на Angular 9.0, собираемые из одного репозитория.

Где

Моя команда известна как ярый адепт продуктов Atlassian, поэтому вся экосистема нашего проекта живет в "австралийских облаках":

  • задачи и релизы в Jira

  • код в Bitbucket

  • CI в Bitbucket Pipelines

  • подробная документация в Confluence.

Наша команда использует стандартный план Bitbucket за $4/чел, включающий в себя 1500 минут сборки в Bitbucket Pipelines. О нем в сегодняшней статье и пойдет речь. Принцип работы и синтаксис настройки на 90 процентов похожи на Gitlab CI, поэтому любому пользователю Gitlab вся схема работы будет максимально понятной.

Сама система интернет банкинга разбита на микросервисы и работает в контейнерах на серверах Банка. Но в этой статье речь будет идти не о контейнерах, хотя настройка CI с помощью Docker-образов звучит очевидным.

Немного контекста

Первые наши шаги в DevOps и конкретно в улучшении QX (QA experience) мы начали задолго до этого в проектах мобильных приложений. Мы интегрировали между собой Jira, Bitbucket и сервис Bitrise.io во всех наших пулл-реквестах, что позволило иметь на выходе конкретный билд на каждый коммит по конкретной задаче. Для наглядности: тестировщик понимал, что пулл реквест 30 выдает билд приложения 170, в которой нужно тестировать Jira-задачу 500. Если вкратце описать процесс пулл-реквестов, то обязательными требованиями к слиянию пулл-реквеста являются

  • Зеленый билд на последнем коммите

  • Добро от разработчика-ревьюера

  • Добро от тестировщика

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

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

Подобного механизма пулл-реквестов никогда не существовало в web приложениях. Мы всегда делали приемку задач после слияния пулл-реквестов в стабильную ветку, из-за чего каждый третий коммит в ней был дефектным. Настроить такой же процесс приема пулл реквестов, как в мобилке, было для нас очевидным шагом. Сделать CI окружение для web приложения на инфраструктуре Банка было для нас слишком долгой историей, потому что хотелось настроить и поехать очень быстро. А все, кто работал с большими банками, почувствовал "скорость" продвижения задач по железу. Все процессы, что мы опишем в этой статье, мы планируем воссоздать в инфраструктуре банка с помощью оркестратора (Kubernetes или OpenShift, на усмотрение заказчика), но это уже другая история. В тот момент нам нужно было как можно быстрее начать работать правильно.

Первый очевидный вопрос: куда доставлять? Мы начали присматриваться к разным вариантам: Heroku, AWS, Netlify, Surge итд. В итоге остановились на использовании AWS S3. Для тех, кто думал, что S3 это всего лишь файловое хранилище - S3 может работать как сайт и его можно привязать к доменному имени. Подробнее об этом можно прочитать на страничке AWS.

Так почему же AWS?

  • Доступная цена. При всей репутации AWS как дорогой экосистемы, ежемесячные счета за S3 выходят в среднем 2 доллара при следующих метриках:

    • Новых ПР в день ~ 2

    • Пайплайнов в день ~ 12

    • Кол-во единовременно существующих бакетов ~ 5

    • Средний размер бакета = 13 Mb

  • У AWS отличный API и CLI. у "Surge" и других легковесных сервисов хостинга не настолько качественный и полноценный тулинг, как у Amazon AWS. Надо отметить, что CLI и документация Heroku не уступает Амазону, но высокий на наш взгляд порог вхождения и специфика работы Heroku Dynos заставили нас отойти от его выбора.

  • У команды уже был опыт работы с продуктами AWS.

Можно было бы настроить весь этот процесс в контейнерах в самом Amazon, но это повлечет за собой запуск EC2 машин. Даже с использованием Docker Hub вместо Elastic Container Registry, прогноз затрат вываливался у нас за $100 в месяц. В конечном итоге у нас получилась именно та схема работы с пулл-реквестами, которую мы представляли себе в самом начале. Но давайте проанализируем каждую ступень нашей эволюции и посмотрим на принятые решения.

Уровень 1: создание S3 бакета

Мы начали с того, что создали по одному выделенному S3 bucket для хостинга клиентского и админского приложений. Настроили конфигурацию сборки нашего проекта (bitbucket-pipelines.yml), чтобы он собирал приложения (html/css/js/img) и заливал их в соответствующий S3 bucket. В начале был использован AWS CLI, но, как оказалось, Bitbucket предоставляет набор готовых официальных Pipes (аналог Github actions), среди которых оказался Pipe для выгрузки файлов в S3 bucket. В итоге: тестировщик имеет сайт, на котором он может проверить реализацию задачи пулл-реквеста с постоянной условной ссылкой web.s3-website.ap-northeast-2.amazonaws.com.

Обязательным предварительным шагом при создании бакета через консоль AWS является включение опции "Enable static hosting" в настройках бакета. Без этой опции bucket является просто файловым хранилищем.

- step:      name: Build and deploy webadmin PR version into AWS for QA      caches:        - node      script:        # начальная конфигурация        - apk update && apk add git        - npm install        # сборка        - npm run build:admin        - cd dist/admin        # загрузка в S3        - pipe: atlassian/aws-s3-deploy:0.2.4          variables:            AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID            AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY            AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION            S3_BUCKET: $S3_WEBADMIN_BUCKET_NAME            DELETE_FLAG: 'true'            LOCAL_PATH: $(pwd)            ACL: 'public-read'

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

Оценка:

  • за старания - четверка

  • за QX - двойка

Уровень 2: выделение S3 bucket под каждого автора

В ответ на обратную связь от тестировщиков командой было решено выделить по одному S3 bucket на каждого фронтенд разработчика. В нашем проекте были разработчики Манар, Миша - следовательно были созданы условные S3 бакеты jsn-web-manar и jsn-web-michael. В bitbucket-pipelines.yml в step для пулл-реквестов была добавлена логика определения конечного S3 бакета в зависимости от PR автора.

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

  1. Гонка пулл-реквестов одного автора. Если один и тот же разработчик создаст 3 параллельных пулл-реквеста, то все они вызовут запуск пайплайна сборки. Мы не можем точно знать, какой из пайплайнов закончится быстрее. Команде, в частности тестировщику, без использования консоли Chrome сложно понять, какой из пулл-реквестов сейчас развернут на S3 бакете разработчика Михаила.

  2. Появление нового автора. В наших репозиториях создавать пулл-реквест может любой член команды, поэтому эта схема сломалась ровно в тот момент, когда ПР создал кто-то, кроме фронтенд-разработчиков. По нашей тривиальной логике определения бакета его запущенный пайплайн "угонит" S3 бакет одного из разработчиков. В итоге другой тестировщик может потерять version-under-test сайт прям в момент тестирования.

  3. Смена никнейма. Наши разработчики забавы ради любят менять свои git author name время от времени. Для нас это никогда не являлось проблемой до того, как мы применили логику с бакетами на каждого автора. К сожалению, Bitbucket Pipelines из коробки не предоставляют возможности определения автора по его Jira account, поэтому в логике присвоения бакета пришлось оперировать стандартным commit git author. Как вы и сами догадались, при смене имени с "Manar Kurmanov" на "Dark Lord" повторилась ситуация из пункта 2 - был угнан бакет другого разработчика.

С этой шаткой схемой команда прожила еще несколько месяцев.

Оценка:

  • за старания - четверка

  • за QX - тройка

Уровень 3: добавление штампа авторства в web приложение

Команда решила проблему гонки пулл-реквестов добавлением пояснительного текста в footer сайта:

Каждый пайплайн добавлял в футер сайта название ветки, автора и timestamp. Таким образом решалась проблема параллельных пулл-реквестов от одного автора - тестировщик четко понимает, какая Jira-задача разработчика Георгия представлена в бакете.

Фрагмент из bitbucket-pipelines.yml

- step:    name: Build PR version    caches:      - node    script:      # initial configuration      - apk update && apk add git      - npm install      # preparing site footer text      - TIMESTAMP_FILE="./src/app/some/folder/copyright.timestamp.html"      - GIT_AUTHOR=$(git log -n 1 --format=format:'%an')      - PR_URL="$BITBUCKET_GIT_HTTP_ORIGIN/pull-requests/$BITBUCKET_PR_ID"      - BRANCH_TEXT="PR branch <a href=\\"$PR_URL\\">$BITBUCKET_BRANCH</a><br>"      - echo $BRANCH_TEXT >> $TIMESTAMP_FILE      - echo "Author $GIT_AUTHOR<br>" >> $TIMESTAMP_FILE      - echo "Built at $(TZ=UTC-6 date '+%d-%m-%Y %H:%M') <br>" >> $TIMESTAMP_FILE      - echo "</small>" >> $TIMESTAMP_FILE      - cat $TIMESTAMP_FILE > src/app/target/folder/copyright.component.html      # building artefacts      - npm run build    artifacts:      paths:        # кеширование артефактов для следующего Build Step         - dist/web/**

Казалось бы, +100 к QX, куда еще прозрачнее. Но поставьте себя на место тестировщика в ежедневной работе и вы поймете еще одно скрытое неудобство. Допустим, что разработчик создал 3 параллельных пулл-реквеста и тестировщик проверил сайт на S3 бакете. Что он должен делать дальше? Тестировщику не очевидно, что он находится в ситуации очереди ПР-ок на один и тот же S3 бакет. После он должен зайти в странице Pipelines, найти нужную ветку и сделать ручной Rerun.

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

Оценка:

  • за старания - четверка

  • за QX - тройка с плюсом

Уровень 4: динамичные бакеты под каждый пулл реквест

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

  • Каждый пулл реквест должен породить свой отдельный S3 бакет и задеплоить сайт туда.

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

  • Автоматика должна уметь подчищать за собой неиспользуемые бакеты

Для реализации этих требований не хватало стандартных Bitbucket Pipes, поэтому нужно было писать кастомные скрипты для взаимодействия с AWS S3. К счастью Bitbucket Pipelines, как и многие CI системы, является cloud-first и предоставляет возможность запускать свои пайплайны на базе любого публичного Docker образа. Мы использовали официальный образ aws-cli, включающий в себя AWS CLI и все базовые утилиты командной строки (curl, sed, xargs).

Ниже фрагмент из bitbucket-pipelines.yml по загрузке статики сайта в динамический бакет. NOTE: в скрипте используются ключи и секреты из учетной записи AWS S3, их можно сгенерировать по официальной инструкции.

- step:    name: Deploy PR version into AWS bucket for QA    image:      name: amazon/aws-cli    script:      # 1. Настройка сессии в aws cli с помощью ключей      - aws configure set aws_access_key_id=$AWS_ACCESS_KEY_ID aws_secret_access_key=$AWS_SECRET_ACCESS_KEY      # 2. определяем название для динамического бакета      - export BUCKET_NAME=web-pullrequest-$BITBUCKET_PR_ID      # 3. если в AWS нету бакета с таким названием, создаем его с нужными флагами      - if [ -z $(aws s3 ls | grep $BUCKET_NAME) ]; then aws s3api create-bucket --bucket $BUCKET_NAME --acl public-read --region ap-northeast-2 --create-bucket-configuration LocationConstraint=ap-northeast-2; fi      # 4. задаем это бакету настройку статичного хостинга      - aws s3api put-bucket-website --website-configuration "{\\"ErrorDocument\\":{\\"Key\\":\\"error.html\\"},\\"IndexDocument\\":{\\"Suffix\\":\\"index.html\\"}}" --bucket $BUCKET_NAME      # 5. очищаем содержимое бакета      - aws s3 rm s3://$BUCKET_NAME --recursive       # 5. заливаем в него собранные html/css/js      - aws s3 cp dist/web s3://$BUCKET_NAME --acl public-read --recursive      # 6. Пишем коммент со ссылкой от имени сервисной учетки в нужный пулл реквест      - export PR_API_URL=https://api.bitbucket.org/2.0/repositories/$BITBUCKET_REPO_FULL_NAME/pullrequests/$BITBUCKET_PR_ID/comments      - export BUCKET_PUBLIC_URL=http://$BUCKET_NAME.s3-website.ap-northeast-2.amazonaws.com      - curl $PR_API_URL -u $CI_BB_USERNAME:$CI_BB_APP_PASSWORD --request POST --header 'Content-Type:application/json' --data "{\\"content\\":{\\"raw\\":\\"[http://$BUCKET_NAME.s3-website.ap-northeast-2.amazonaws.com](http://personeltest.ru/away/$BUCKET_NAME.s3-website.ap-northeast-2.amazonaws.com)\\"}}"

В качестве автора комментарий в пулл реквест мы использовали нашу сервисную учетную запись для CI с использованием App-specific password. В этой статье от Atlassian можно узнать, как создать такой пароль.

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

"Единственный ручной процесс в этой схеме - чистка неиспользуемых S3 бакетов раз в неделю. Зачем это автоматизировать?" - подумали мы. Но по закону жанра команда благополучно забывала подчищать бакеты и вспомнила об этом только после того, как бухгалтер показал счет на 25 долларов от AWS из-за скопившихся бакетов.

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

- step:    name: Remove dangling s3 buckets left after PR merges    image:        name: amazon/aws-cli    script:      # 1. Запросить список 10 последних MERGED пулл реквестов      - export API_URL="<https://api.bitbucket.org/2.0/repositories/$BITBUCKET_REPO_FULL_NAME/pullrequests?state=MERGED>"      - curl "$API_URL" -u $CI_BB_USERNAME:$CI_BB_APP_PASSWORD > pr_list.json      # 2. выделить бакеты, соответствующие спец-формату       - aws s3 ls | grep -o '[a-zA-Z\\-]\\+pullrequest\\-[0-9]\\+' > buckets.txt- set +e      # очистить все бакеты с номер ПР-ок, которые уже MERGED      # (AWS API требует очистки бакета перед его полным удалением)      - echo "$(cat pr_list.json | grep -o '"id":\\s[0-9]\\+')" | sed 's/[^0-9]//g' | xargs -I{} grep {} buckets.txt | xargs -I{} aws s3 rm s3://{} --recursive      # удалить все бакеты с номер ПР-ок, которые уже MERGED      - echo "$(cat pr_list.json | grep -o '"id":\\s[0-9]\\+')" | sed 's/[^0-9]//g' | xargs -I{} grep {} buckets.txt | xargs -I{} aws s3api delete-bucket --bucket {}

Оценка:

  • За старания пятерочка

  • за QX - четверка с плюсом. Почему не пять? Потому что на своей шкуре мы поняли, что улучшение любого X (QX, DevX, HX) - это бесконечный процесс

Технические ремарки

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

#1: По поводу CORS

Так как API запросы совершаются с одного хоста (.amazonaws.com) на другой хост (*.somebank.com), по умолчанию они будут блокироваться браузером из-за настроек CORS (cross origin resource sharing) сервера. Если вкратце, то браузер позволяет отправлять запросы только из того же хоста, откуда сайт был запрошен. Для примера, API на api.server.com будет принимать запросы только с сайта server.com. При попытке сделать GET запрос с сайта another.com браузер сначала совершит "pre-flight" запрос на сервер и поймет, что сервер строго выдерживает правило "same-origin-policy".

Для того, чтобы запросы со статичного сайта S3 бакета проходили в ваш API, вы должны добавить хост бакета в серверные настройки Headers.

Access-Control-Allow-Origin: <http://bucket.s3-website.amazonaws.com># илиAccess-Control-Allow-Origin: *

Во всех популярных фреймворках есть поддержка управления Cross Origin.

#2: По поводу расходов

В уровне 4 в скрипте присутствует строка очистки содержимого бакета:

aws s3 rm s3://$BUCKET_NAME --recursive 

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

Если этого не делать, то размер бакета будет увеличиваться пропорционально кол-ву пайплайнов на 1 ПР. В масштабах 3 разработчиков это экономит нам пару центов, но в масштабе десяток разработчиков и долгих ПР - это десятки долларов. Мы считаем, что это полезное упражнение как минимум с точки зрения практики владения AWS API.

ВАЖНО! Если в вашем проекте будет использоваться долгоживущий S3 bucket и вы будете использовать официальный aws-s3-deploy pipe, то убедитесь, что вы используете DELETE_FLAG. Этот флаг очищает bucket перед очередной выгрузкой файлов. Во время уровня #1 наша команда об этом флаге не знала в течение 2 месяцев и узнала только после обнаружения нескольких тысяч файлов в одном бакете. Поэтому парочку десяток американских долларов было сожжено во имя наших познаний.

# вызов пайпа загрузки файлов в S3 с флагом DELETE_FLAG- pipe: atlassian/aws-s3-deploy:0.2.4    variables:      AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID      AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY      AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION      S3_BUCKET: $S3_WEBADMIN_BUCKET_NAME      DELETE_FLAG: 'true' # не забыть этот флаг      LOCAL_PATH: $(pwd)      ACL: 'public-read'

Вывод

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

Финальную версию bitbucket-pipelines.yml можно посмотреть в github репозитории.

Материалы к прочтению

Подробнее..
Категории: S3 , Angular , Devops , Frontend , Amazon web services , Aws , Cicd , Pipelines , Bitbucket

CICD для проекта в GitHub с развертыванием на AWSEC2

05.01.2021 00:04:18 | Автор: admin

Имеем: проект web API на.net core с исходниками в GitHub.

Хотим: авторазвертывание на виртуалке AWS EC2 после завершения работы с кодом (для примера push в develop ветку).

Инструментарий: GitHub Actions, AWS CodeDeploy, S3, EC2.

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

Basic CI/CDflowBasic CI/CDflow

1. Пользователи и роли

1.1. Пользователь для доступа к к AWS из GitHub Action

Этот пользователь будет использоваться для подключения к AWS сервисам S3 и CodeDeploy через AWS CLI 2 при запуске GitHub Actions.

1. Заходим в консоль AWS IAM, слева в меню User, и Add User

2. Задаем произвольное имя и ставим галочку Programmatic access

Создание нового пользователяСоздание нового пользователя

3. Далее, в разделе Permissions выбираем Attach existing policies directly и добавляем политики AmazonS3FullAccess и AWSCodeDeployDeployerAccess.

4. Тэги можно пропустить, на этапе Review должно получиться следующее:

Итоговый результатИтоговый результат

5. Жмем Create user и сохраняем данные пользователя у себя. Нам понадобятся Access Key ID и Secret Access Key позднее.

1.2. Сервисная роль для инстансов AWS EC2

Роль необходимо будет навесить на инстансы EC2, на которых будем производить развертывание, чтобы они могли взаимодействовать с сервисом AWS CodeDeploy.

  1. Заходим в консоль AWS IAM, слева в меню Role, и Add Role

  2. Выбираем AWS Service, в Choose a use case выбираем EC2 и переходим далее

  3. Находим и добавляем политику AmazonEC2RoleforAWSCodeDeploy.

  4. Тэги и Review пропускаем

  5. Называем роль, например, ProjectXCodeDeployInstanceRole и на этапе Review должно получиться следующее:

1.3. Сервисная роль для AWS CodeDeploy

Роль позволяет сервису AWS CodeDeploy обращаться к инстансам AWS EC2.

1. Заходим в консоль AWS IAM, слева в меню Role, и Add Role

2. Выбираем AWS Service, в Use case выбираем CodeDeploy:

Создание ролиСоздание роли

3. Переходим далее, нужная политика нам уже добавлена автоматом (AWSCodeDeployRole)

4. Называем роль, например, ProjectXCodeDeploy и на этапе Review должно получиться следующее:

Итоговый результат создания ролиИтоговый результат создания роли

2. Инстанс AWSEC2

  1. Разворачиваем подходящий инстанс в AWS EC2

  2. Назначаем ему роль ProjectXCodeDeployInstanceRole, созданную на этапе 1.2

  3. Устанавливаем CodeDeploy Agent на инстанс. Как это сделать смотрим по ссылке.

Важно: Если агента установили на машину до того, как навесили роль, то агента необходимо перезапустить командой sudo service codedeploy-agent restart

3. Конфигурация AWS CodeDeploy

1. Переходим в консоль AWS CodeDeploy

2. Слева в меню кликаем Deploy, внутри Applications

3. Создаем новое приложение кликнув Create application

4. Вводим произвольное имя, например, projectx и выбираем Compute platform EC2/On-Premises

Новое приложениеНовое приложение

5. Далее, провалившись в приложение кликаем Create deployment group

6. Назваем произвольно, develop в нашем случае. Роль выбираем ту, что создале в разделе 1.3 выше (ProjectXCodeDeploy).

7. Deployment type выбираем In place (для примера подойдет).

8. В разделе Environment configuration выбираем Amazon EC2 Instances и далее с помощью тэгов находим подходящие инстансы.

4. Создаем бакет на AWSS3

Для размещения новых сборок нам понадобится бакет в AWS S3.

  1. Заходим в консоль AWS S3, кликаем Create bucket.

  2. Называем, например, projectx-codedeploy-deployments. Убеждаемся что стоит галочка Block all public access. И после кликаем Create bucket.

Создание нового бакета S3Создание нового бакета S3

5. Создаем appspec.yml

Для того, чтобы CodeDeploy Agent понимал как работать с нашим приложением при получении новой сборки нужно ему об этом рассказать. В AWS CodeDeploy для этого нужен специальный файл в корне сборки под названием appspec.yml. В нашей задачке он выглядит следующим образом:

version: 0.0os: linuxfiles:  - source: /    destination: /opt/projectxpermissions:  - object: /opt/projectx    owner: ubuntu    group: ubuntu    type:      - directory      - filehooks:  ApplicationStart:    - location: scripts/start_server.sh      timeout: 300      runas: ubuntu  ApplicationStop:    - location: scripts/stop_server.sh      timeout: 300      runas: ubuntu
  1. Создаем appspec.yml version: 0.0 os: linux files:

В двух словах мы сообщаем, где исходники (строка 4), куда их разворачивать (строка 5) и с какими правами (строки 6-12). В разделе хуков мы говорим как поднимать и останавливать приложение. Подробнее по структуре и хукам на события можно почитать в документации.

Важно: Версию надо ставить 0.0, т.к. иначе ругается CodeDeploy и в веб-консоли будет ошибка что версия должна быть именно 0.0 \_()/. Второй момент: при первом деплойменте нужно закомментнтить хук ApplicationStop, иначе на нем будет падать развертывание. Связано это с тем, что агент пытается найти скрипты остановки в прошлом развертывании, которого еще не случилось. Второе и последующие развертывания работают с ApplicationStop корректно.

6. Настраиваем GitHubActions

Подобрались к самому интересному, настало время описать CI/CD pipeline на базе GitHub Actions.

6.1. Создаем секреты

На странице проекта в GitHub кликаем вкладку Settings, далее в меню слева Secrets и добавляем два секрета:

  • AWS_ACCESS_KEY_ID: значение мы сохранили на шаге 5 раздела 1.1 по созданию пользователь для доступа к AWS

  • AWS_SECRET_ACCESS_KEY: значение мы сохранили на шаге 5 раздела 1.1 по созданию пользователь для доступа к AWS

6.2. Настраиваем пайплайн

Создаем в корне приложения директорию .github/workflows. В ней будут размещаться наши файлы с описанием pipeline'ов. Создаем первый, например, develop.yaml. У нас получилось следующее:

name: build-app-actionon:   push:    branches:      - developjobs:  build:    name: CI part    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v2      - name: Setup .NET Core        uses: actions/setup-dotnet@v1        with:          dotnet-version: 5.0.101      - name: Install dependencies        run: dotnet restore      - name: Build        run: dotnet build --configuration Release --no-restore    deploy:    name: CD part    runs-on: ubuntu-latest    strategy:      matrix:        app-name: ['projectx']        s3-bucket: ['projectx-codedeploy-deployments']        s3-filename: ['develop-aws-codedeploy-${{ github.sha }}']        deploy-group: ['develop']    needs: build    steps:      - uses: actions/checkout@v2      # set up .net core      - name: Setup .NET Core        uses: actions/setup-dotnet@v1        with:          dotnet-version: 5.0.101      # restore packages and build      - name: Install dependencies        run: dotnet restore      - name: Build        run: dotnet build ProjectX --configuration Release --no-restore -o ./bin/app      # copying appspec file      - name: Copying appspec.yml        run: cp appspec.yml ./bin/app      # copying scripts      - name: Copying scripts        run: cp -R ./scripts ./bin/app/scripts            # Install AWS CLI 2      - name: Install AWS CLI 2        run: |          curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"          unzip awscliv2.zip          sudo ./aws/install      # Configure AWS credentials      - name: Configure AWS Credentials        uses: aws-actions/configure-aws-credentials@v1        with:          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}          aws-region: ap-south-1      # Deploy push to S3      - name: AWS Deploy push        run: |          aws deploy push \          --application-name ${{ matrix.app-name }} \          --description "Revision of the ${{ matrix.appname }}-${{ github.sha }}" \          --ignore-hidden-files \          --s3-location s3://${{ matrix.s3-bucket }}/${{ matrix.s3-filename }}.zip \          --source ./bin/app      # Creating deployment via CodeDeploy      - name: Creating AWS Deployment        run: |          aws deploy create-deployment \          --application-name ${{ matrix.app-name }} \          --deployment-config-name CodeDeployDefault.AllAtOnce \          --deployment-group-name ${{ matrix.deploy-group }} \          --file-exists-behavior OVERWRITE \          --s3-location bucket=${{ matrix.s3-bucket }},key=${{ matrix.s3-filename }}.zip,bundleType=zip \

Глобально у нас два джоба: сборка и развертывание, причем первое является пререквизитом второго (раздел needs в deploy, строка 31). Срабатывание пайплайна в примере я настроил на push в ветку develop (строки 2-5).

Шаг build

Мы устанавливаем.net, скачиваем нужные пакеты и собираем проект. Именно это и указывается в строках 11-19. Сборку мы проводим на Ubuntu (строки 9 и 23) Здесь же можно прогнать unit-тесты. Если всё случилось, переходим к шагу deploy.

Шаг deploy

Создаем стратегию типа матрицы с параметрами для сборки.

  • app-name: название приложения как завели на шаге 4 раздела 3 по конфигурации CodeDeploy

  • s3-bucket: название бакета, который создали на шаге 2 раздела 4

  • s3-filename: шаблон имени файла для размещения в бакете, используем хэш коммита

  • deploy-group: название группы развертывания как завели на шаге 6 раздела 3.

Первые два шага аналогичны build: ставим.net, качаем пакеты, собираем приложение (тут точечно указан проект, т.к., например, тесты нам не нужны в артефакте, который собираемся катить) и складываем его в отдельную папку (./bin/app в нашем случае, строка 48). Копируем в папку с собранным приложением файл appspec.yml и скрипты запуска и остановки приложения (строки 43-48). Далее со строки 51 мы используем AWS CLI v2, который есть в виде готового action в маркетплейсе GitHub. Устанавливаем AWS CLI2, используем ключи от учетной записи из секретов GitHub проекта, которые настроили чуть выше в разделе 6.1, и указываем регион AWS. Загружаем в AWS S3 собранный проект. Создаем новое развертывание в AWS CodeDeploy. На этом заканчивается работа GitHub Actions.

После этого уже AWS CodeDeploy уведомит EC2 инстансы, которые были в нем настроены, о наличии новой сборки, CodeDeploy Agent на них сходит в AWS S3 за новой версией и развернет её. Понаблюдать за этим можно уже из консоли AWS CodeDeploy.

Резюмируем

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

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

Подробнее..
Категории: Ci/cd , Devops , Github actions , Amazon web services , Aws

Перевод Как я получил несколько сертификатов по облачным технологиям за 9 месяцев

10.02.2021 10:11:22 | Автор: admin

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

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

Простая мотивирующая история с полезными ссылками.

Почему облачные технологии?

Ты присоединился к EPAM Anywhere в качестве DevOps инженера. Почему ты решил развиваться в облачных технологиях?

Как и многие коллеги из моей области, я начал свою карьеру в ИТ в качестве системного администратора, а затем постепенно переходил к методологиям DevOps.

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

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

Первые шаги в облаке

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

Часть сертификатов ты получил самостоятельно, а остальные через EPAM Global Certification, верно?

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

В результате я прошел сертификацию AWS Cloud Practitioner и AWS Developer (Associate) до работы в EPAM, потом, будучи в EPAM, успешно сдал экзамен на AWS DevOps Engineer (Professional).

Помимо программы сертификации AWS, я принял участие в программе сертификации Microsoft Azure для сотрудников EPAM и прошел четыре сертификации: Azure Fundamentals; Azure Developer (Associate) и после небольшого перерыва архитектор решений Azure (Azure Solutions Architect Expert). Недавно я сертифицировался на Azure Data Scientist Associate.

От сертификатов AWS и Microsoft Azure до Google Cloud

Почему ты решил получить сертификат Google Cloud?

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

Затем я прочитал историю успеха о нашем коллеге, который получил ряд профессиональных сертификатов GCP, благодаря чему попал на новый интересный проект. Думаю, это послужило толчком для меня, я подал заявку на ещё одну сертификацию GCP и получил сертификат GCP Cloud Engineer (Associate).

Но это еще не конец истории. Поскольку я был на волне самообразования, я также решил изучить Kubernetes и, наконец, сдал экзамен на Kubernetes Application Developer (CKAD).

Сколько сертификатов сейчас в твоём портфолио?

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

Что, по-твоему, является самой сложной частью процесса сертификации и как с ней справиться?

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

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

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

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

Секреты успеха: ключевые принципы, которые помогут получить желаемые сертификаты

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

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

Также очень выгодно соответствовать ритму программы, в которой вы участвуете. Например, в одно время мне потребовалось 9 месяцев, чтобы завершить свои программы сертификации Azure, GCP и Kubernetes я сдавал экзамены каждые шесть недель.

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

  • Мотивация, основанная на понимании преимуществ, которые сертификация даст для профессионального роста.

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

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

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

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

Двигайтесь вперед и никогда не останавливайтесь на пути к своей мечте!

Подробнее..

Выбор оптимальной платформы для веб приложения

29.03.2021 10:21:19 | Автор: admin

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

Проблемы внедрения

Как уже упоминалось выше, запустить веб-приложение можно на разных платформах. Можно на собственных серверах компании, можно использовать Shared Hosting провайдеров, можно приобрести VPS/VDS хостинг, например, у DigitalOcean, а можно для размещения вашего веб-приложения использовать облачную инфраструктуру от интернет гигантов -Amazon Web Services (AWS), Google Cloud, Microsoft Azure и так далее. Существуют также и специально ориентированные на хостинг веб-приложений решения вроде Pantheon или WP Engine.

Множество возможных решений вызывает головную боль у новичка. Что выбрать? Что дешевле? Что надежнее? Где лучше техподдержка? Где больше возможностей и где лучше перспектива роста? Давайте рассмотрим плюсы и минусы каждого из вариантов.

Dedicated server

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

Shared Hosting

Если вы решили использовать Shared Hosting, то со стоимостью необходимых затрат наоборот, все хорошо. Это, пожалуй, самое дешевое решение. К тому же часто дополнительно вы получаете бесплатные доменные имена. Ваш сервер настроен и в общем-то не требует специальных технических знаний для использования. Все обслуживается и администрируется службой поддержки сервис провайдера. Но при этом вы крайне ограничены в добавлении и конфигурировании дополнительных возможностей для вашего проекта. Более того, производительность и стабильность вашего веб-приложения может серьезно пострадать из за внезапных и значительных потоков трафика ипотребления ресурсов сервера соседними сайтами и веб-приложениями. А таких прожорливых соседей у вас может быть несколько сотен! Оперативности технической поддержки при таком количестве клиентов скорее всего не следует ожидать. Кроме того, остро стоит вопрос безопасности shared hosting-а, ведь если хотя бы один из сайтов или веб-приложений будет взломан злоумышленниками, скорее всего они сумеют получить доступ и к ресурсам других проектов на этом сервере. По этим и другим причинам рынок shared hosting стагнирует в последние годы.

VPS Hosting

Одно из самых популярных решений. У многих на слуху компания DigitalOcean со своими популярными предложениями. Виртуальные приватные сервера дороже, чем Shared Hosting, на за эту разницу в цене вы получаете выделенные только для вас ресурсы на сервере, соседи по серверу не влияют на производительность вашего веб-приложения, конфигурируемость очень высокая поскольку вы имеете полный root доступ к вашей системе и тем самым имеете полное право навыполнение всех без исключения операций. Удобно вертикально масштабировать ваш VPS вручную и с даунтаймом. Достаточно остановить VPS, добавить ресурсов и снова запустить. С физическим сервером такое не пройдет. Но опять же, помимо достаточно ощутимой цены,тут требуется высокая квалификация и серьезные технические знания по управлению серверами. По сути, нужны специалисты такого же уровня, как и для управления физическими серверами, разница только в том, что нет проблем с hardware (не нужен план замен, закупок, монтажа и тому подобное), но инфраструктурно всё то же самое. Поэтому и для VPS hosting нужны высококвалифицированные администраторы.Чтобы сконфигурировать рабочее окружение для вашего веб-приложения и поддерживать его, вам потребуется немало времени.

Managed Hosting

Вариант хостинга, когда для вас запускают конкретное веб приложение, дают вам административный доступ в него, но непосредственное управление сервером осуществляется не вами. Таким образом, вы ограничены только вашим приложением. Управлять вы можете только тем, что оно позволяет делать в своих рамках. А поскольку таких как вы много на физическом сервере, то возникают все те же проблемы, которые характерны для Shared hosting -нестабильность объёма фактически доступных ресурсов, медленный ответ техподдержки и так далее.

Clouds

Давайте тут остановимся подробнее. Динамика роста популярности облачных решений в последние годы впечатляет. Аналитическая компания Gartner оценила объем мирового рынка публичных облачных сервисов в $242,7 млрд по итогам 2019 года. В 2021 году глобальный рынок внедрения облачных технологий превысит в общей сложности $306 млрд по данным той жеGartner. Решения на базе облачных технологий выбирают для себя компании и организации независимо от своего размера. Каждый находит в них для себя что-то свое, но общие преимущества облачных решений очевидны:

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

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

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

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

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

Но при всех преимуществах облачных технологий, в процессе их внедрения в работу компании, неизменно возникает проблема высокого порога вхождения. Она заключается в сложности выбора облачной архитектуры. Например, непросто выбрать подходящий для вашего проекта AWS stack, который обеспечивал бы все потребности и его стоимость не выходила бы за рамки бюджета. Вообще, если мы говорить об AWS, то его можно представить себе в виде некого конструктора, изкоторого вы можете сделать много разного - главное уметь это делать. Организацию хостинга веб-приложения с помощью AWS порой сравнивают со сборкой компьютера (по сравнению с покупкой готового - заказа хостинга у провайдера):EC2-это материнская плата и память. Онпозволяет запускать instance на базе образа операционной системы.EBS-это как диск. Вы можете сказать: сделай мне диск размером в 45 гигабайт и подключи его к такому-то instance (созданный "диск" будет называться volume). В результате в вашей системе появляется новое устройство, которое вы можете монтировать, форматировать и работать с ним. Все, что было записано на него, сохраняется независимо от жизни instance.S3-это как внешнее хранилище. Туда можно сохранять большие файлы и хранить их там вечно. А есть еще сервисы для логирования, мониторинга, баз данных, DNS и множество других. Как собрать из этого набора комплектующих именно тот "компьютер", или AWS stack, который обеспечит оптимальную работу вашего приложения и при этом не переплатить?Новичку в облачных технологиях непонятно, какую конкретно схему AWS stack использовать, какие выбрать сервисы и компоненты, как их соединять между собой. Оценить сложность выбора можно по вот этой схемеCNCF Cloud Native Landscape.

Усложняет задачу выбора и тот факт, что для использования AWS Cost Forecast или калькулятора для расчета расходов от пользователя требуются специфические знания и навыки. Кроме того, весьма сложно создать описания процессов, структуры и необходимых скриптов. Все это требует наличия высококвалифицированных специалистов, глубоко разбирающихся в облачных технологиях Amazon, Google или Microsoft.

В общем, главный минус хостинга в облаках - он сложный.

App-specificproviders

Если рассматривать услуги App-specific providers, которые рассчитаны в первую очередь на разработчиков, то широко известными примерами таких сервисов являются Google AppEngine, VMWare Pivotal Cloud Foundry, Heroku, Pantheon и другие. Такиесервисы представляют наборы готовых компонентов для создания приложений, а также фреймворки для управления платформой. В данном случае компонентами будут являться сервисы баз данных, репозитории, инструменты автоматизированного деплоя, мониторинга, среды тестирования и тому подобные сервисы.

Уровень входа в эти сервисы ниже, чем в облачные, но тем не менее, для развертывания хостинга вашего приложения на таких системах, какHeroku или Pantheon требуется написание специального манифеста,разрабатывать и отлаживать который для новичков очень непросто.Недостатки напоминают таковые у Managed hosting - ты имеешь только то, что тебе дают. При этом часто чего-то не додают, например, нужную конкретную версию компонента. Кроме того, неудобны ценовые планы - вы либоне помещаетесь в план, либо платите за большие ресурсы, чем потребляет ваш проект. В итоге часто получается так, что в процессе роста ваше приложение начинает обходиться слишком дорого, но так как вы уже адаптировали его для конкретного PaaS, перейти на какое-то другое решение вам уже сложно.Но при этом у App-specific providers нет проблемы выбора и соединения множества компонентов, как у AWS или других облачных провайдеров.

Предлагаемое решение

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

  • AWS account

  • GIT account

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

Кастомизация и отличия от конкурентов

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

Масштабируемость

В отличие от решений масштабируемости, которые предлагают сервис провайдеры,WSP предоставляет возможность использовать autoscaling, или, иначе говоря, горизонтальнуюмасштабируемость. Autoscaling легко настраивается в зависимости от потребностей работы вашего приложения. Учитывая, что вы платите только за фактически используемые ресурсы, autoscaling становится очень выгодным решением. Если нагрузка снижается, избыточные серверные мощности высвобождаются, соответственно вы платите меньше.

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

Наскриншоте нижехорошо видно, как просто это можно настроить:

Мониторинг и логи

Настройка систем мониторинга и логирования крайне нетривиальная задача в AWS. В WSP логирование с помощью ELK stack (Elasticsearch, Logstash, Kibana) и мониторинг с использованием Prometheus или Grafana настраиваются и подключаютсяпредельно просто. То есть, ониподключаются автоматически к каждому приложению,если при регистрацииAWS аккаунта к WSP было выбрано использование этой функциональности. В то же время вы всегда можете отключить мониторинг и логи, например, для экономии. И наоброт, включить их, когда они потребуются.

Так как мониторинг и логирование разворачиваются в AWS аккаунте, то они входит в стоимость AWS. Следовательно эти функции не исчезают даже если вы отказались от использования WSP.

Управление затратами

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

Технические домены с сертификатами

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

Автоматическое развертывание баз данных в Amazon RDS

WSP может автоматически разворачивать экземпляр базы данных типа PostgreSQL, MySQL или MariaDB для вашего приложения в Amazon RDS. Это настраивается непосредственно в "Environment settings" вашго приложения:

Zero downtime

Если в процессе работы с вашим приложением WSP производит развертывание новой версии приложения или откат на предыдущую версию, сессия работы переключается с текущей на новую версию приложения совершенно незаметно для вас. Реализован полный Zero Downtime для таких случаев.

One more thing!

  • Lift&Shift. Особенное внимание в разработке и концепции WSP уделяется тому, что вам совершенно не нужно как-то адаптировать и переделывать ваше приложение для его работы в облаке. С помощью WSP оно будет работать без каких то дополнительных усилий для его адаптации.

  • В WSP ограничение доступа к вашим приложениям обеспечивается с помощью Access Rules. Вы можете добавить в них те сети и адреса, с которых возможен доступ. Со всех иных сетей и адресов доступ будет закрыт.

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

  • Все используемые в продукте компоненты стандартные. Эти компоненты- признанный мировой стандарт индустрии, имеют открытый исходный код и бесплатны.Никакие проприетарные компоненты не используются. Например, для pipeline в WSP используется Tekton.

  • Все секретные данные, такие, например, как пароли, логины и т.д. шифруются.

  • Поддерживается непрерывное развертывание (Continuous Deployment (CD)). То есть, платформа может автоматически собирать и разворачивать приложение по коммиту в GIT репозитории.

  • В настоящее время в качестве поддержки концепции "Infrastructure as a code" WSP может считывать параметры приложения из специальных файлов из git-репозитория, то есть кроме задания параметров приложения из UI возможно задавать параметры в файле.

Планы дальнейшего развития

В настоящее время WSP работает только с облачной инфрастуктурой Amazon. В дальнейшем планируется расширить этот список облачными сервисами Google, Microsoft Azure и DigitalOcean. Для тех потребителей, кто использует инфрастуктуру на базе Kubernetes также планируется поддержка.

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

Заключение

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

Проект находится еще в очень ранней стадии развития. Фаза активной разработки продолжается. В настоящее время команда Pleskуже использует WSP для наших собственных сервисов. Если вы хотите попробовать WSP, посмотреть, подходит ли он для вас, повлиять на развитие проекта путём обратной связи, поделиться вашими сценариями использования - welcome to closed alpha. Присоединиться можноздесь.

Подробнее..

И еще разок про Serverless

15.03.2021 14:07:31 | Автор: admin
Логотип AWS Lambda (ну или Half Life, я так и не понял)Логотип AWS Lambda (ну или Half Life, я так и не понял)

С публичного релиза AWS Lambda прошло ни много ни мало 6 с лишним лет. Реактивные функции, реагирующие на события, не только позволили по-другому смотреть на архитектуру систем и приложений, но и породили новый buzzword Serverless.

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

Мой пост будет опираться на технологии, разработанные в компании AWS, но тезисы из него применимы как к другим облачным провайдерам (GCP, Azure), так и к "домашним" имплементациям (OpenFaaS).


Я собираюсь пройтись по трем, на мой взгляд самым важным, пунктам, касающимся Serverless

  • Сначала я "демистифицирую" понятие Serverless, отделив его от реактивных функций Lambda,

  • Затем я пройдусь по архитектуре Lambda

  • И закончу этот пост рядом рекомендаций по разработке и сопровождению Serverless приложений.

В дальнейшем я буду использовать sls для обозначения Serverless. Я очень ленивый.

Lambda != Serverless, Lambda in Serverless == True

Горе павшим жертвами сладких речей адвокатов и евангелистов! "Вам не нужно будет управлять парком машин!", "Вы сможете развернуть свое приложение за считанные секунды!", "С помощью sls эффективность вашей разработки возрастет в разы!", - это и многое другое пытаются втолкнуть мне толпы героев и евангелистов AWS, но я познал суть.

Видите ли, риторика "мне не нужно думать об инфраструктуре" обречена на провал. Разве код работает в воздухе? Разве он не нуждается в сети? Разве мне нужно заботиться об инфраструктуре, если у меня есть Kubernetes, и я просто объявляю в нем сущности?

На мой взгляд, лучше всего преимущество sls описал Рик Хулихан на своем докладе посвященному архитектурным паттернам DynamoDB, кратко затронув новую парадигму (весь доклад сам по себе интересный, но ссылка ведет на последние несколько минут).

Fail cheap - вот, что конкурентно "продает" sls. Чтобы проверить тезис, мне не нужно так много ресурсов, как понадобилось бы чтобы развернуть небольшой кластер из виртуалок или контейнеров. Скорость здесь - не решающий фактор. В 2021-ом году, что Lambda функция, что таблица DynamoDB, что контейнер в ECS/EKS, что экземпляр EC2 - все это запускается в считанные минуты, если не секунды.

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

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

Что такое Serverless

AWS предоставляет огромный набор сервисов для построение систем различной степени нагрузки и тяжести, часть из которых имеет бирку sls - очереди и потоковая обработка (SQS, Kinesis), нотификации (SES, SNS), интеграции (EventBridge, Step Functions), хранилище (S3), базы данных (DynamoDB), работа с данными (Glue, Athena). Если вы смотрели мое выступление на HighLoad++, вы помните, как именно я отличаю sls от "обычных" сервисов. Sls создает для вас отдельный уровень абстракции, снимая с вас операционную нагрузку по работе с сервисом (на самом деле нет - теперь вам надо учить новую технологию/подход).

Взять к примеру базы данных DynamoDB - сама СУБД уже есть! В ваше пользование предоставляется таблица с ее "пропускной способностью" (WCU/RCU), индексы и прочие фичи. В случае с сервисом ETL Glue вас не допускают к работе с самим движком ETL - вместо этого вы объявлете схему трансформации данных, указываете источник и пункт назначения данных, а так же описываете задачу. Все остальное находится вне вашего ведения и управления, чтобы вы себе лишний раз ногу не отстрелили (если очень хотите отстрелить - поднимайте свое на виртуалках ЕС2).

Отличие будет в биллинге. Если в случае с базами RDS и задачами ECS Fargate где оплата идет поминутно (или посекундно?), с sls вы платите за объем (сколько гигабайт "весят" данные в S3) и утилизацию (запросы и трафик).

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

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

Ничего сложного, верно? Основное непонимание связано как раз с отсутствием простой истины в умах: sls - это абстракция над PaaS, которая тарифицируется по-другому.

Отсюда и сложности с sls приложениями. Sls приложение - не только набор Lambda функций за API GW. Sls приложение состоит только из sls сервисов.

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

Архитектура AWS Lambda

Родоначальница sls подхода вызвала в своей время немало шума, ведь ее релиз пришелся на то же время, что и буря вокруг Docker и рождение Kubernetes. За простотой Lambda функций (далее - Функция) стоит определенная хитрость, ведь мысль о том, что "просто нужно написать код и запустить" вызывает недоверие.

На самом же деле Функции несколько сложнее, чем звучат из сладких уст многочисленных sls евангелистов и героев, (и порождают не меньше сложностей, но об этом позже). Архитектура Функции состоит из 3 частей: Источник События (Triggering Event); внутренности AWS Lambda - runtime, deployment package (логика с зависимостями), слои (layers) и "дополнение" (extensions); точка назначения Функции (если имеется) - корзина S3, таблица DynamoDB, очередь SQS и т.д.

Картинка посвящается Ване Моисееву - моему другу и любителю иконок AWSКартинка посвящается Ване Моисееву - моему другу и любителю иконок AWS

В довесок к этому идут еще мониторинг, трассировка запроса и многие прелести, например Lambda Permission - а именно "разрешение" какому-то внешнему ресурсу (генератору событий) запускать Функции, передавая им полезную нагрузку (Событие).

Что происходит под капотом Lambda - история куда сложнее, и лучше послушать о ней из первоисточника.

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

Как жить с Lambda

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

  1. Локальная разработка и отладка

  2. Архитектура sls приложений

  3. Организация кодовой базы

  4. Развертывание

  5. Эксплуатация (логирование, мониторинг, трассировка)

  6. Безопасность

Звучит сложно? Ну передавайте от меня привет тем, кто говорил, что sls это легко.

1. Локальная разработка и отладка

Стоит первым пунктом потому, что с этого все и начинается. AWS завез прекрасный инструмент под названием Serverless Application Model или SAM.

SAM представляет собой два компонента: интерфейс командной строки aws-sam-cli (ставится как через brew так и через pip) и шаблон (сильно упрощенный CloudFormation).

Для отладки Функции нужно объявить ее в шаблоне. Затем можно будет вызывать ее двумя способами: sam local invokeили sam local start-api(для Функций, отвечающих на вызовы API GW).

Если вы впервые видите SAM, то проще всего запустить один из quick start шаблонов, заботливо приготовленных для вас инженерами AWS.

$ sam initWhich template source would you like to use?1 - AWS Quick Start Templates2 - Custom Template LocationChoice: 1What package type would you like to use?1 - Zip (artifact is a zip uploaded to S3)2 - Image (artifact is an image uploaded to an ECR image repository)Package type: 1Which runtime would you like to use?1 - nodejs12.x2 - python3.83 - ruby2.74 - go1.x5 - java116 - dotnetcore3.17 - nodejs10.x8 - python3.79 - python3.610 - python2.711 - ruby2.512 - java8.al213 - java814 - dotnetcore2.1Runtime: 2Project name [sam-app]:Cloning app templates from https://github.com/aws/aws-sam-cli-app-templatesAWS quick start application templates:1 - Hello World Example2 - EventBridge Hello World3 - EventBridge App from scratch (100+ Event Schemas)4 - Step Functions Sample App (Stock Trader)5 - Elastic File System Sample AppTemplate selection: 1    -----------------------    Generating application:    -----------------------    Name: sam-app    Runtime: python3.8    Dependency Manager: pip    Application Template: hello-world    Output Directory: .    Next steps can be found in the README file at ./sam-app/README.md

Пройдя в sam-appможно вызвать функцию локально (первый запуск займет некоторое время, образ Lambda runtime нужно скачать):

$ sam local invoke HelloWorldFunctionInvoking app.lambda_handler (python3.8)Image was not found.Building image.......................................Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-python3.8:rapid-1.15.0.Mounting /Users/karentovmasyan/Development/Personal/dummy_project/sam-app/hello_world as /var/task:ro,delegated inside runtime containerSTART RequestId: e7036160-e11c-440a-b089-8099b1e0d500 Version: $LATESTEND RequestId: e7036160-e11c-440a-b089-8099b1e0d500REPORT RequestId: e7036160-e11c-440a-b089-8099b1e0d500Init Duration: 0.29 msDuration: 114.08 msBilled Duration: 200 msMemory Size: 128 MBMax Memory Used: 128 MB{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}%

А установив плагин для JetBrain IDE или VS Code можно использовать и полноценный отладчик, чтобы узнать, где конкретно входящий JSON неправильно обрабатывается!

2. Архитектура sls приложений

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

Давайте представим некий market-service для биржи, который имплементирует API GET /markets. Вызовы на этот API вернут нам список текущих рынков, базовых валют, по прямому запросу - тикер.

С точки зрения микросервисов это может имплементировать один сервис, в котором будут реализованы следующие API:

GET /marketsGET /markets/baseGET /markets/ticker?pair=USD-RUB

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

Реализовать такой функционал в Lambda тоже можно в одной функции. Полезная нагрузка в запросе будет выглядеть следующим образом (при условии, что запрос пришел из API GW):

# GET /markets{  # some params...  "resource": "/markets",  "path": "/markets",  "headers": #...  "queryStringParameters": null,  # etc...}# GET /markets/ticker?pair=USD-RUB{  # some params...  "resource": "/markets/ticker",  "path": "/markets/ticker",  "queryStringParameters": {  "pair": "USD-RUB"}} 

Мы можем осуществить проверку пути/ресурса и в зависимости от этого реализовать логику одной функции. Что-то навроде:

def get_markets():  passdef get_ticker(pair):  passdef handler(event, context):  path = event.get('path')  if path == '/markets':    return get_markets()  elif path == '/markets/ticker':    return get_ticker(event.get('queryStringParameters').get('pair'))

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

  1. Тарификация Функции идет по времени выполнения и мы тратим драгоценное время на избыточный control flow.

  2. Если Функция должна "ходить" в несколько мест (S3, DynamoDB и прочие API AWS), то мы даем ей опасно большое количество разрешений.

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

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

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

3. Организация кодовой базы

Подход выше открывает 2 проблемы: управление общим кодом (что если 90% кода в Функциях одинаковые? Где моя бритва?!) и организация репозитория.

Раньше чтобы запаковать Функцию с зависимостями, нужно было создавать специальный deployment package и загружать его на S3. Что вручную, что с SAM это представляет собой следующее:

$ pip install -t . -r requirements.txt$ zip -r lambda.zip .$ aws s3 cp lambda.zip s3://bucket_name/

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

Для компилируемых языков проблема не такая неприятная, управление зависимостями пройдет на стадии сборки. Для интерепретируемых языков, таких как Python, JavaScript и Ruby, проблема решается с помощью слоев (Lambda Layers). Слои Функций работают по схожему принципу со слоями контейнерных образов и предоставляют собой отдельное хранилище, монтируемое к runtime'у Функции.

Таким образом, проект можно организовать следующим образом:

$ tree -L 2. README.md  requirements.txt src # исходный код  lambda # handler'ы приложения  lib # общие библиотеки template.yaml tests venv

В шаблоне SAM можно указать директорию, чтобы создать нужный слой:

Resources:  Layer:    Type: AWS::Serverless::LayerVersion    Properties:      CompatibleRuntimes:          - python3.6          - python3.7          - python3.8          - python3.9      ContentUri: 'src/lib'

Ну и дальше дело техники - в ресурсе функции указать версию слоя, ссылаясь на нее в самом же шаблоне с помощью Fn::Ref.

Resources:  MarketsGet:    Type: AWS::Serverless::Function    Properties:      CodeUri: src/lambda/markets/get      Handler: markets_get.handler      Layers:        - !Ref Layer      Events:        ApiEvent:          Type: Api          Properties:            Path: /markets            RestApiId: !Ref Api            Method: get

Возникает вопрос: "А что делать, если в одном репозитории мне нужны разные версии зависимостей?" С помощью Слоев эта проблема не решается. Самое правильное - собрать, упаковать и положить зависимость в репозиторий. В случае с Python - Pip server.

4. Развертывание

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

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

SAM хорош тем, что создает абстракцию над CloudFormation для упрощенного объявления ресурсов sls приложений. В свою очередь Антон Бабенко сделал похожий инструмент для TF. Выбирать между одним или вторым я не буду (в тусовке амазонщиков у меня уже есть репутация "хейтера" Terraform), а разбор отличий заслуживает отдельной статьи.

Все еще живой Serverless framework тоже управляет жизненным циклом sls приложений (сам я с ним не работал, так что на ваш страх и риск).

Ну и вишенка на торте и вершина айсберга Хайпа - Cloud Development Kit или CDK. В отличие от выше описанных инструментов CDK объявляет инфраструктуру с использованием высокоуровневых языков программирования (TypeScript, JavaScript, Python, C#, Java), код которых компилируется ("синтезируется") в шаблон CloudFormation. Похожую историю имплементировали и ребята из HashiCorp, назвав ее cdktf.

Архитектура CDK/cdktf сама по себе сложная, но это не выступает барьером, который даже неопытные инженеры-облачники не в состоянии предолодеть. В сети полно материалов, как блогов, так и self-paced workshop, лекций, CDK day - их море.

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

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

В остальном развертывание sls приложений ничем не отличается от развертывания других приложений на AWS - у вас имеется цепочка поставки (pipeline), которая прогоняет тесты, пакует ресурсы и раскатывает их по различным регионам и аккаунтам. Делаете вы это с помощью sam deployили terraform apply- не так уж и важно.

5. Эксплуатация

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

Отладить простейшую CRUD-функцию тоже много ума не надо. Прилетел JSON в Функцию, с ним что-то произошло, выхлоп лег куда-то. Если что-то в этом потоке пошло не так, достаточно локально отладить Функцию с помощью того же SAM CLI, приложив к ней багообразующий event.

Другое дело, если Функций много и работают они в каком-то долгом транзакционном процессе, наппример Step Functions. Отлавливать логи по времени, как прилетел злосчастный запрос, который не смог корректно обработать - то еще приключение, и разработчик может потратить неприемлемо много времени, чтобы найти баг.

На помощь придет инструмент observability от AWS под названием X-Ray. X-Ray является сервисом трассировки, он тесно интегрирован в sls экосистему. Достаточно включить поддержку X-Ray в Функции, и каждому запросу начнет присваиваться нужный идентификатор.

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

6. Безопасность

С очевидными вещами разбираться не будем. Всем известны такие базовые паттерны безопасности, как шифрование (at-rest, in-transit) и контроль сетевого периметра c помощью NACL и Security Groups.

У каждой Функции должна быть своя IAM роль. И по лучшим практикам безопасности каждая роль должна следовать least-privilege principle - то есть не даем больше прав, чем минимально нужно для работы приложения.

Иными словами, если наша Функция выполняет операцию dynamodb:PutItem, как минимум странно давать роли разрешение dynamodb:*(разрешаем все действия по отношению к DynamoDB). Так же странно видеть Resource: "*", в то время как работа идет в отношении одной таблицы.

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

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

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

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

Бояться тут надо не того, что кто-то взломает Функцию и изнутри нее будет делать всякие глупости (такая вероятность есть, но это тема другой статьи), но того, что роль Функции кто-то может assume, т.е. "принять на себя". Именно таким образом взломали Capital One: не взломали сервер, а просто получили ARN роли, через которую получили STS ключ, секрет и токен. Потому что кто-то ошибся в поле Principal. Стыд!


Вроде ничего не забыл? Я не ожидаю, что после прочтения вы сразу побежите писать Lambda функции и хвастаться стремительно сокращаюимся парком EC2 машин. Ниже я прилагаю ссылки, которые позволят вам двигаться дальше в изучении Serverless и Lambda в частности:

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

Подробнее..
Категории: Lambda , Amazon web services , Aws , Cloudnative , Serverless

Категории

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

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